简体   繁体   中英

Android Custom View, anchor image at center of analog clock

I am creating a custom analog clock with images for hour, second, minute hands. The clock works fine but only problem is the anchoring of the hands. Below is an image of the clock attached. The hour, minute hands are anchored at the center which makes the clock look bad. All the hands should be anchored at the edges so that it looks more realistic and readable. Can someone suggest something. My custom view is attached here.

package com.example.submission_customclock;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.Handler;
import android.text.format.Time;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews.RemoteView;
import java.util.TimeZone;

/**
 * This widget display an analogic clock with two hands for hours and
 * minutes.
 *
 * @attr ref android.R.styleable#AnalogClock_dial
 * @attr ref android.R.styleable#AnalogClock_hand_hour
 * @attr ref android.R.styleable#AnalogClock_hand_minute
 */

@RemoteView
public class AnalogClock extends View {
    private Time mCalendar;
    private static final String DEBUGTAG = "FA";
    private Drawable mHourHand;
    private Drawable mMinuteHand;
    private Drawable mSecondHand;
    private Drawable mDial;
    private Drawable mDial_frame;


    private int mDialWidth;
    private int mDialHeight;

    private boolean mAttached;

    private final Handler mHandler = new Handler();
    private float mMinutes;
    private float mHour;
    private boolean mChanged;

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

    public AnalogClock(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    Context mContext;
    public AnalogClock(Context context, AttributeSet attrs,
                       int defStyle) {  
        super(context, attrs, defStyle);
        Resources r = context.getResources();
        mContext=context;
        Log.d(AnalogClock.DEBUGTAG,"Analog clock started");


       mDial = r.getDrawable(R.drawable.clock4);
       mDial_frame = r.getDrawable(R.drawable.clock_frame);
       mHourHand = r.getDrawable(R.drawable.hour_hand);
       mMinuteHand = r.getDrawable(R.drawable.minute_hand);
       mSecondHand = r.getDrawable(R.drawable.second_hand);

        mCalendar = new Time();

        mDialWidth = mDial.getIntrinsicWidth();    
        mDialHeight = mDial.getIntrinsicHeight();
    }

    @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);

            getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
        }

        // NOTE: It's safe to do these after registering the receiver since the receiver always runs
        // in the main thread, therefore the receiver can't run before this method returns.

        // The time zone may have changed while the receiver wasn't registered, so update the Time
        mCalendar = new Time();

        // Make sure we update to the current time
        onTimeChanged();
        counter.start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mAttached) {
            counter.cancel();
            getContext().unregisterReceiver(mIntentReceiver);
            mAttached = false;
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    @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);

        float hScale = 1.0f;
        float vScale = 1.0f;

        if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
            hScale = (float) widthSize / (float) mDialWidth;
        }

        if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
            vScale = (float )heightSize / (float) mDialHeight;
        }

        float scale = Math.min(hScale, vScale);
        Log.d(AnalogClock.DEBUGTAG,"onMeasure params: " + widthSize + " " 
                + heightSize + " " + hScale + " " + vScale + " " + scale); 

        try {
            setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
                   resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

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

    boolean mSeconds=false;
    float mSecond=0;
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        boolean changed = mChanged;
        if (changed) {
            mChanged = false;
        }

        boolean seconds = mSeconds;
        if (seconds ) {
            mSeconds = false;
        }
        int availableWidth = this.getMeasuredWidth();
        int availableHeight = this.getMeasuredHeight();

        int x = availableWidth / 2;
        int y = availableHeight / 2;

        final Drawable dial = mDial;
        final Drawable dial_frame = mDial_frame;
        int w = dial.getIntrinsicWidth();
        int h = dial.getIntrinsicHeight();
        boolean scaled = false;
       // Log.d(AnalogClock.DEBUGTAG,"onDraw params: " + availableWidth +" "+  availableHeight + " " +
        //      x + " " + y + " " + w + " "+ h + " " + changed);

        if (availableWidth < w || availableHeight < h) {
            scaled = true;
            //float scale = Math.min((float) availableWidth / (float) w,
              //                     (float) availableHeight / (float) h);
            canvas.save();
            float scale1 = (float) 0.6;
            float scale2 = (float) 0.8;

          //  Log.d(AnalogClock.DEBUGTAG,"scale params: " + scale1 + " " + scale2);
            canvas.scale(scale1, scale2, x, y);
        }

        if (changed) {
            //Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2)) + " " + (y - (h / 2)) + " " + ( x + (w / 2)) + " " + (y + (h / 2)));
            dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
            //dial_frame.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
            //Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2 + w/10)) + " " + (y - (h / 2 + h/10)) + " " + ( x + (w / 2 + w/10)) + " " + 
              //         (y + (h / 2 + h/10)));
            dial_frame.setBounds(x - (w/2 + w/10), y - (h/2 + h/10), x + (w/2 + w/10), y + (h/2 + h/10));
        }
        dial.draw(canvas);
        dial_frame.draw(canvas);


        canvas.save();
        canvas.rotate(mHour / 12.0f * 180.0f, x, y);
        final Drawable hourHand = mHourHand;
        if (changed) {
            w = hourHand.getIntrinsicWidth();
            h = hourHand.getIntrinsicHeight();
            hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
        }
        hourHand.draw(canvas);
        canvas.restore();

        canvas.save();
        canvas.rotate(mMinutes / 60.0f * 180.0f, x, y);

        final Drawable minuteHand = mMinuteHand;
        if (changed) {
            w = minuteHand.getIntrinsicWidth();
            h = minuteHand.getIntrinsicHeight();
            minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
        }
        minuteHand.draw(canvas);
        canvas.restore();
        canvas.save();
        canvas.rotate(mSecond, x, y);

        if (seconds) {
            w = mSecondHand.getIntrinsicWidth();
            h = mSecondHand.getIntrinsicHeight();
            mSecondHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
        }
        mSecondHand.draw(canvas);
        canvas.restore();

        if (scaled) {
            canvas.restore();
        }
    }
    MyCount counter = new MyCount(10000, 1000);

    public class MyCount extends CountDownTimer{
        public MyCount(long millisInFuture, long countDownInterval) {
        super(millisInFuture, countDownInterval);
        }

        @Override
        public void onFinish() {
            counter.start();
        }

        @Override
        public void onTick(long millisUntilFinished) {
            mCalendar.setToNow();

            int second = mCalendar.second;

              mSecond=6.0f*second;
            mSeconds=true;
             //mChanged = true;
             AnalogClock.this.invalidate();
         }
     }

    private void onTimeChanged() {
        mCalendar.setToNow();

        int hour = mCalendar.hour;
        int minute = mCalendar.minute;
        int second = mCalendar.second;

        mMinutes = minute + second / 60.0f;
        mHour = hour + mMinutes / 60.0f;
        mChanged = true;
    }

    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
                String tz = intent.getStringExtra("time-zone");
                mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
            }

            onTimeChanged();

            invalidate();
        }
    };
}

在此处输入图片说明

您的问题是drawable folder clock_frame ,minute_hand,hour_hand and second_hand 特定尺寸 。例如,如果您使用240 x 240 clockframe则应该take minutes_hand,hour_hand和second_hand设置19 x 240并且这些指针应从上到下与比较的时钟框架的中心位置。如果您要更时尚,您可以从clock_frame中心位置稍微clock_frame距离。

最简单的方法是将指针的位图设置为与刻度盘相同的大小,然后旋转至12点钟。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM