问题描述
有下一个阶段:
Scale和对齐定制的Android AnalogClock手
...这个。
It is the next stage of:Scale and align in custom android AnalogClock hands...this one.
我很快意识到,一个可绘制无法进行缩放,如果它符合尺寸框,然后它就会显示出来。否则不是。所以现在我需要一个位图缩放,然后转换回可绘制和绘制。它似乎并不优雅,但据我发现,我没有看到任何其他方式。
Soon I realized that a Drawable can not be scaled, if it fits the size box, then it will be displayed. Otherwise not. So now I need a Bitmap to scale it and then convert back to Drawable and draw it. It doesn't seem elegant, but according to what I found, I don't see any other way.
(想法是创建自己的闹钟应用有一些特殊的技巧。首先,我需要的时钟指针。用于创建自定义的时钟,我用自己的类,它扩展视图。时针和分针的PNG图像。它们应设在屏幕的中心,但他们甚至不可见的。模拟器不显示时钟在所有,不扔任何ecxeptions(显示基本层))
(Idea is to create own alarm app with some special tricks. Firstly, I need clock hands. For creating custom clock, I used own class, which extends View. Hour and minute hands are PNG images. They should be located in the center of the screen, but they are not even visible. Emulator do not display the clock at all, and is not throwing any ecxeptions (basic layer is displayed))
同样,我需要的屏幕尺寸设置时针和分针的大小。在code现在看起来:
Again I need screen dimensions to set up size of Hour and Minute hands. The code now looks as:
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
import android.widget.ImageView;
@SuppressLint("NewApi")
public class Clock extends ImageView {
private Drawable mHourHand;
private Drawable mMinuteHand;
private int sizeXHour;
private int sizeXMinute;
private int sizeYHour;
private int sizeYMinute;
private int xHour;
private int xMinute;
private int yHour;
private int yMinute;
private int w;
private int h;
private Drawable Hh;
private Bitmap HourHnd;
private Drawable Mh;
private Bitmap MinuteHnd;
private boolean mAttached;
static private float mMinutes;
static private float mHour;
private boolean mChanged;
Context mContext;
// Getters&setters
protected float getmMinutes() {
return mMinutes;
}
protected static void setmMinutes(float mMinutes) {
Clock.mMinutes = mMinutes;
}
protected float getmHour() {
return mHour;
}
protected static void setmHour(float mHour) {
Clock.mHour = mHour;
}
//Ctors
@SuppressWarnings("deprecation")
public Clock(Context context) {
super(context);
Resources r = context.getResources();
mContext=context;
Hh = r.getDrawable(R.drawable.hours);
HourHnd = ((BitmapDrawable)Hh).getBitmap();
Mh = r.getDrawable(R.drawable.minuts);
MinuteHnd = ((BitmapDrawable)Mh).getBitmap();
// Here I try to take screen dimensions
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR2)
{
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
h = metrics.heightPixels;
w = metrics.widthPixels;
}
else
{
Display d = wm.getDefaultDisplay();
h = d.getWidth();
w = d.getHeight();
}
sizeXHour = w/3;
sizeYHour = Hh.getIntrinsicHeight()*sizeXHour/Hh.getIntrinsicWidth();
xHour = sizeXHour/2;
yHour = sizeYHour/2;
mHourHand = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(HourHnd, sizeXHour, sizeYHour, true)); // Here it says that sizeXHour etc. is 0;
sizeYMinute = h/4;
sizeXMinute = Mh.getIntrinsicWidth()*sizeYMinute/Mh.getIntrinsicHeight();
xMinute = sizeXMinute/2;
yMinute = sizeYMinute/2;
mMinuteHand = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(MinuteHnd, sizeXMinute, sizeYMinute, true));
setWillNotDraw(false);
}
@SuppressWarnings("deprecation")
public Clock(Context context, AttributeSet attrs) {
this(context, attrs, 0);
//setWillNotDraw(false);
Resources r = context.getResources();
mContext=context;
Hh = r.getDrawable(R.drawable.hours);
HourHnd = ((BitmapDrawable)Hh).getBitmap();
Mh = r.getDrawable(R.drawable.minuts);
MinuteHnd = ((BitmapDrawable)Mh).getBitmap();
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
//if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR2)
//{
//DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
//h = metrics.heightPixels;
//w = metrics.widthPixels;
//}
//else
//{
Display d = wm.getDefaultDisplay();
h = d.getWidth();
w = d.getHeight();
//}
sizeXHour = w/3;
sizeYHour = Hh.getIntrinsicHeight()*sizeXHour/Hh.getIntrinsicWidth();
xHour = sizeXHour/2;
yHour = sizeYHour/2;
mHourHand = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(HourHnd, sizeXHour, sizeYHour, true));
sizeYMinute = h/4;
sizeXMinute = Mh.getIntrinsicWidth()*sizeYMinute/Mh.getIntrinsicHeight();
xMinute = sizeXMinute/2;
yMinute = sizeYMinute/2;
mMinuteHand = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(MinuteHnd, sizeXMinute, sizeYMinute, true));
setWillNotDraw(false);
}
@SuppressWarnings("deprecation")
public Clock(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
Resources r = context.getResources();
//TypedArray a =
//context.obtainStyledAttributes(attrs, R.styleable.AnalogClock, defStyle, 0);
mContext=context;
//mHourHand = r.getDrawable(R.drawable.hours);
Hh = r.getDrawable(R.drawable.hours);
HourHnd = ((BitmapDrawable)Hh).getBitmap();
//mMinuteHand = r.getDrawable(R.drawable.minuts);
Mh = r.getDrawable(R.drawable.minuts);
MinuteHnd = ((BitmapDrawable)Mh).getBitmap();
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
//if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR2)
//{
// DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
//h = metrics.heightPixels;
// w = metrics.widthPixels;
//h = size.x;
//w = size.y;
//}
//else
// {
Display d = wm.getDefaultDisplay();
h = d.getWidth();
w = d.getHeight();
//}
sizeXHour = w/3;
sizeYHour = Hh.getIntrinsicHeight()*sizeXHour/Hh.getIntrinsicWidth();
xHour = sizeXHour/2;
yHour = sizeYHour/2;
mHourHand = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(HourHnd, sizeXHour, sizeYHour, true));
sizeYMinute = h/4;
sizeXMinute = Mh.getIntrinsicWidth()*sizeYMinute/Mh.getIntrinsicHeight();
xMinute = sizeXMinute/2;
yMinute = sizeYMinute/2;
mMinuteHand = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(MinuteHnd, sizeXMinute, sizeYMinute, true));
setWillNotDraw(false);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
//int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width = widthSize;
int height = heightSize;
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mChanged = true;
this.invalidate();
}
@SuppressWarnings({ "deprecation" })
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
boolean changed = mChanged;
if (changed) {
mChanged = false;
}
canvas.rotate(mHour / 12.0f * 360.0f, xHour, yHour);
if (changed) {
mHourHand.setBounds((w / 2) - xHour, (h / 2) - yHour, sizeXHour, sizeYHour);
}
mHourHand.draw(canvas);
//canvas.restore();
canvas.save();
canvas.rotate(mMinutes / 60.0f * 360.0f, xMinute, yMinute);
if (changed) {
mMinuteHand.setBounds((w / 2 - xMinute), (h / 2 - yMinute), sizeXMinute, sizeYMinute);
/
}
mMinuteHand.draw(canvas);
//canvas.restore();
canvas.save();
}
}
抱歉,大型$ C $再次℃。现在,在Eclipse图形布局管理规定这个错误:
Sorry for that large code again. Now the graphic layout manager in Eclipse states this error:
java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:808)
at android.graphics.Bitmap.createBitmap(Bitmap.java:787)
at android.graphics.Bitmap.createBitmap(Bitmap.java:719)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:595)
at ee.st.running.dreamyclock.Clock.<init>(Clock.java:268)
at ee.st.running.dreamyclock.Clock.<init>(Clock.java:161)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0( at sun.reflect.NativeConstructorAccessorImpl.newInstance( at sun.reflect.DelegatingConstructorAccessorImpl.newInstance( at java.lang.reflect.Constructor.newInstance( at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.instantiateClass(ProjectCallback.java:438)
at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.loadView(ProjectCallback.java:190)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:207)
at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:132)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:802)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:778)
at android.view.LayoutInflater.inflate(LayoutInflater.java:500)
at android.view.LayoutInflater.inflate(LayoutInflater.java:381)
在结果sizeXHour等为0;我不知道该时钟指针将在所有的绘制,但我需要收购仍然屏幕尺寸。是否有任何可能的想法?
In result, sizeXHour etc is 0; I am not sure that clock hands will be drawn at all, but I need to acquire screen dimensions nevertheless. Are there any possible ideas?
P.S。例外的是首先在这里:
mHourHand =新BitmapDrawable(getResources(),Bitmap.createScaledBitmap(HourHnd,sizeXHour,sizeYHour,真实));
P.S. Exception is firstly here: mHourHand = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(HourHnd, sizeXHour, sizeYHour, true));
推荐答案
所以,此异常出现因为Eclipse不能完全解决一些属性,如样式等..它在可视化编辑器发生错误时解释说。有些解决方法是使用 View.isInEditMode()
。
So this exception appears because eclipse cannot fully resolve some attributes such as styles, etc ... It is explained in the visual editor when the error occurs. Some workaround is to use View.isInEditMode()
.
至于让屏幕的大小,code使用(与显示
)是正确的,应该工作。如果时钟没有出现,这意味着别的东西是错误的,而不是测量。
As for getting the size of the screen, the code you use (with Display
) is correct and should work. If the clock doesn't appear, this means something else is wrong, not measurements.
我认为衡量屏幕的大小,一般一个坏主意,因为你让你的看法整个屏幕相匹配的假设。但没有prevents视图放置一些其他的容器内,因此有一个真正的大小是较小的。
I consider measuring the size of the screen a bad idea in general, because you make the assumption that your view matches the whole screen. But nothing prevents your view to be placed inside some other container and therefore have a real size that's smaller.
我建议的话,你用用 View.getWith()视图的边界
和 View.getHeight()
。
注:由于观点施工后测量,使用这些方法在构造函数返回0。你必须要等到观点已经奠定了检索其尺寸:使用此 View.getViewTreeObserver() .setOnGlobalLayoutListener
。
I suggest then, that you use the bounds of your view using View.getWith()
and View.getHeight()
.Note : since a view is measured after its construction, using these methods in the constructors returns 0. You have to wait until the view has been laid out to retrieve its dimension : use for this View.getViewTreeObserver().setOnGlobalLayoutListener
.
还有:
-
你的看法是奠定了之后,
的onDraw
将自动被调用,所以没有必要调用无效
在onMeasure
。
After your view is laid out,
onDraw
will automatically be called, so there's no need to callinvalidate
at the end ofonMeasure
.
布尔改变没有效果(似乎)。如果当时的想法是用它来只允许绘制的时钟。如果大小改变,这是一个坏主意。这会导致你的看法被抹去时,它是无效的,直到它的边界变化
The boolean changed has no effect (it seems). If the idea was to use it to only allow drawing the clock if size changed, it is a bad idea : this will result in your view being 'erased' when it is invalidated until its bounds change.
这是我如何做它的工作:
Here is how i made it work :
@SuppressLint("NewApi")
public class Clock extends View {
private Drawable mHourHand;
private Drawable mMinuteHand;
private Drawable Hh;
private Drawable Mh;
private boolean mAttached;
static private float mMinutes = 43;
static private float mHour = 5;
Context mContext;
// Getters&setters
protected float getmMinutes() {
return mMinutes;
}
protected static void setmMinutes(float mMinutes) {
Clock.mMinutes = mMinutes;
}
protected float getmHour() {
return mHour;
}
protected static void setmHour(float mHour) {
Clock.mHour = mHour;
}
// Ctors
{
initView();
}
public Clock(Context context) {
super(context);
}
public Clock(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public Clock(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private void initView() {
Resources r = getContext().getResources();
mContext = getContext();
Hh = r.getDrawable(R.drawable.hours);
Mh = r.getDrawable(R.drawable.minuts);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int w = r - l;
int h = b - t;
mHourHand = Hh;
mMinuteHand = Mh;
// They will always be drawn centered inside the view
mHourHand.setBounds(
(w - mHourHand.getIntrinsicWidth()) / 2,
(h - mHourHand.getIntrinsicHeight()) / 2,
(w + mHourHand.getIntrinsicWidth()) / 2,
(h + mHourHand.getIntrinsicHeight()) / 2
);
mMinuteHand.setBounds(
(w - mMinuteHand.getIntrinsicWidth()) / 2,
(h - mMinuteHand.getIntrinsicHeight()) / 2,
(w + mMinuteHand.getIntrinsicWidth()) / 2,
(h + mMinuteHand.getIntrinsicHeight()) / 2
);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Rotate the center of the view (here the canvas is clipped and translated so that its clipped bounds are these of this view).
canvas.save();
canvas.rotate(mHour * 360/12, getWidth()/2, getHeight()/2);
mHourHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mMinutes * 360/12, getWidth()/2, getHeight()/2);
mMinuteHand.draw(canvas);
canvas.restore();
}
}
那么,这里有一个测试,内部的 ActivityInstrumentationTestCase2
运行:
public void test() throws InterruptedException {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
getActivity().setContentView(R.layout.clock_layout);
}
});
Thread.sleep(3000);
}
和布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="ee.st.running.dreamyclock.MainActivity"
android:background ="@drawable/clockk" >
<View
android:id="@+id/view1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!-- A modified layout params to match_parent, wrap_content results in the view having size (0,0) -->
<com.example.clock.Clock
android:id="@+id/clock"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignTop="@+id/view1"
android:layout_centerHorizontal="true" />
</RelativeLayout>
我不明白你所有的缩放code,所以我只是摆脱了它,并尽可能简单,您就可以再从这个工作,如果需要添加一些调整大小code。
I didn't understood all your scaling code, so i just got rid of it, and made as simple as possible, you can then work from this and add some resizing code if needed.
这篇关于Android的显示尺寸和绘制对象大小缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!