安卓自定義時鐘控件實現

近期項目需求,在桌面做一個時鐘,先上效果圖

實現原理,自己做一個時鐘背景,時針,分針,秒針,通過獲取系統時間來控制時分秒針的角度,實現代碼如下
 


package com.cultraview.mlauncher.view;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.RemoteViews.RemoteView;
import java.util.TimeZone;

import com.cultraview.mlauncher.R;

@RemoteView
public class MKAnalogClock extends View {
    private String TAG;

    private boolean mAttached;

    private Time mCalendar;

    private boolean mChanged;

    private Drawable mDial;

    private int mDialHeight;

    private int mDialWidth;

    private Drawable mDot;

    private final Handler mHandler;

    private float mHour;

    private Drawable mHourHand;

    private final BroadcastReceiver mIntentReceiver;

    private Drawable mMinuteHand;

    private float mMinutes;

    private int mSecond;

    private Drawable mSecondHand;

    private Handler mSecondHandler;

    private SecondThread mTimeThread;

    private static final class SecondThread extends Thread {
        private boolean isRunning = true;

        private Handler myHandler;

        private int mySecond;

        SecondThread(int second, Handler handler) {
            setSecond(second);
            this.myHandler = handler;
        }

        void setRunning(boolean running) {
            this.isRunning = running;
        }

        void setSecond(int second) {
            this.mySecond = second;
        }

        public void run() {
            while (this.isRunning) {
                this.myHandler.sendEmptyMessage(this.mySecond);
                if (this.mySecond == 59) {
                    this.mySecond = 0;
                } else {
                    this.mySecond++;
                }
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    Log.d("MKAnalogClock", "error=" + e.getMessage());
                }
            }
        }
    }

    public MKAnalogClock(Context context) {
        this(context, null);
    }

    public MKAnalogClock(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MKAnalogClock(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.mHandler = new Handler();
        this.TAG = getClass().getSimpleName();
        this.mSecondHandler = new Handler() {
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                MKAnalogClock.this.mSecond = msg.what;
                MKAnalogClock.this.postInvalidate();
            }
        };
        this.mIntentReceiver = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals("android.intent.action.TIMEZONE_CHANGED")) {
                    MKAnalogClock.this.mCalendar = new Time(TimeZone.getTimeZone(
                            intent.getStringExtra("time-zone")).getID());
                }
                MKAnalogClock.this.onTimeChanged();
            }
        };
        Resources r = this.mContext.getResources();
        if (this.mDot == null) {
            this.mDot = r.getDrawable(R.drawable.clock_hand_dot);
        }
        if (this.mDial == null) {
            this.mDial = r.getDrawable(R.drawable.clock_dial);
        }
        if (this.mHourHand == null) {
            this.mHourHand = r.getDrawable(R.drawable.clock_hand_hour);
        }
        if (this.mMinuteHand == null) {
            this.mMinuteHand = r.getDrawable(R.drawable.clock_hand_minute);
        }
        if (this.mSecondHand == null) {
            this.mSecondHand = r.getDrawable(R.drawable.clock_hand_second);
        }
        this.mCalendar = new Time();
        this.mDialWidth = this.mDial.getIntrinsicWidth();
        this.mDialHeight = this.mDial.getIntrinsicHeight();
    }

    protected void onAttachedToWindow() { //監聽時間廣播
        super.onAttachedToWindow();
        if (!this.mAttached) {
            this.mAttached = true;
            IntentFilter filter = new IntentFilter();
            filter.addAction("android.intent.action.TIME_TICK");
            filter.addAction("android.intent.action.TIME_SET");
            filter.addAction("android.intent.action.TIMEZONE_CHANGED");
            getContext().registerReceiver(this.mIntentReceiver, filter, null, this.mHandler);
        }
        this.mCalendar = new Time();
        onTimeChanged();
    }

    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (this.mAttached) {
            getContext().unregisterReceiver(this.mIntentReceiver);
            this.mAttached = false;
        }
        if (this.mTimeThread != null) {
            this.mTimeThread.setRunning(false);
        }
    }

    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);
        float hScale = 1.0f;
        float vScale = 1.0f;
        if (widthMode != 0 && widthSize < this.mDialWidth) {
            hScale = ((float) widthSize) / ((float) this.mDialWidth);
        }
        if (heightMode != 0 && heightSize < this.mDialHeight) {
            vScale = ((float) heightSize) / ((float) this.mDialHeight);
        }
        float scale = Math.min(hScale, vScale);
        setMeasuredDimension(this.mDialWidth, this.mDialHeight);
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.mChanged = true;
    }

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        boolean changed = this.mChanged;
        if (changed) {
            this.mChanged = false;
        }
        int availableWidth = this.mRight - this.mLeft;
        int availableHeight = this.mBottom - this.mTop;
        int x = availableWidth / 2;
        int y = availableHeight / 2;
        Drawable dial = this.mDial;
        int w = dial.getIntrinsicWidth();
        int h = dial.getIntrinsicHeight();
        boolean scaled = false;
        if (availableWidth < w || availableHeight < h) {
            scaled = true;
            float scale = Math.min(((float) availableWidth) / ((float) w),
                    ((float) availableHeight) / ((float) h));
            canvas.save();
            canvas.scale(scale, scale, (float) x, (float) y);
        }
        if (changed) {
            dial.setBounds(x - (w / 2), y - (h / 2), (w / 2) + x, (h / 2) + y);
        }
        dial.draw(canvas);
        canvas.save();
        canvas.rotate((this.mHour / 12.0f) * 360.0f, (float) x, (float) y);
        Drawable hourHand = this.mHourHand;
        w = hourHand.getIntrinsicWidth();
        h = hourHand.getIntrinsicHeight();
        Paint paintHour = new Paint();
        paintHour.setStrokeWidth(6.0f);
        paintHour.setAntiAlias(true);
        Canvas canvas2 = canvas;
        canvas2.drawLine((float) x, (float) y, (float) x, (float) ((y - h) + 15), paintHour);
        canvas.restore();
        canvas.save();
        canvas.rotate((this.mMinutes / 60.0f) * 360.0f, (float) x, (float) y);
        Drawable minuteHand = this.mMinuteHand;
        w = minuteHand.getIntrinsicWidth();
        h = minuteHand.getIntrinsicHeight();
        Paint paintMinute = new Paint();
        paintMinute.setStrokeWidth(4.0f);
        paintMinute.setAntiAlias(true);
        canvas.drawLine((float) x, (float) y, (float) x, (float) ((y - h) + 16), paintMinute);
        canvas.restore();
        canvas.rotate((((float) this.mSecond) / 60.0f) * 360.0f, (float) x, (float) y);
        Drawable secondHand = this.mSecondHand;
        w = secondHand.getIntrinsicWidth();
        h = secondHand.getIntrinsicHeight();
        Paint paintSecond = new Paint();
        paintSecond.setStrokeWidth(2.0f);
        paintSecond.setAntiAlias(true);
        canvas.drawLine((float) x, (float) (y + 20), (float) x, (float) ((y - h) + 23), paintSecond);
        Drawable dot = this.mDot;
        w = dot.getIntrinsicWidth();
        h = dot.getIntrinsicHeight();
        if (changed) {
            dot.setBounds(x - (w / 2), y - (h / 2), (w / 2) + x, (h / 2) + y);
        }
        dot.draw(canvas);
        if (scaled) {
            Log.d(this.TAG, "scale ture");
            canvas.restore();
        }
    }

    private void onTimeChanged() {
        this.mCalendar.setToNow();
        int hour = this.mCalendar.hour;
        int minute = this.mCalendar.minute;
        this.mSecond = this.mCalendar.second;
        this.mMinutes = ((float) minute) + (((float) this.mSecond) / 60.0f);
        this.mHour = ((float) hour) + (this.mMinutes / 60.0f);
        this.mChanged = true;
        if (this.mTimeThread != null) {
            this.mTimeThread.setSecond(this.mSecond);
        } else {
            this.mTimeThread = new SecondThread(this.mSecond, this.mSecondHandler);
            this.mTimeThread.start();
        }
        updateContentDescription(this.mCalendar);
    }

    private void updateContentDescription(Time time) {
        setContentDescription(DateUtils.formatDateTime(this.mContext, time.toMillis(false), 129));
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章