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.
(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))
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();
}
}
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)
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. Exception is firstly here: mHourHand = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(HourHnd, sizeXHour, sizeYHour, true));