Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 自定義view實現表盤效果

android 自定義view實現表盤效果

編輯:關於Android編程

周末沒事在家想干點啥,記得一年多前面試,那公司直接發個面試題讓我做,其中就有讓我做一個簡單的表盤效果,不過當時沒做出來,所以也沒好意思去面試,今天就實現下,大概分如下幾步

第一步:畫一個簡單的圓

第二步:繪制刻度

第三步:繪制時,分,表指針

第四步:繪制當前時間文字

第五步:實現時間動態顯示

 

第一步畫一個圓是很簡單的,

package com.example.clockview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
 * Created by Adminis on 2016/11/6.
 */
public class ClockView extends ImageView {
    private static final String TAG = "ClockView";
    private Paint mPaint;
    private int widhth = 200;//控件的寬度
    private int height = 200;//控件的高度
    private int padding = 5;
    public ClockView(Context context) {
        this(context, null);
    }
    public ClockView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widhth, height);
    }
    private void initPaint() {
        mPaint = new Paint();
        mPaint.setStrokeWidth(3);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.parseColor("#666666"));
        mPaint.setAntiAlias(true);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        drawCircle(canvas);
    }
    /**
     * 繪制圓
     * @param canvas
     */
    private void drawCircle(Canvas canvas) {
         mPaint.setStyle(Paint.Style.STROKE);
         canvas.drawCircle(widhth/2,height/2,widhth/2-padding,mPaint);
    }
}

 

第二步:繪制刻度

 

/**
 * 繪制刻度
 * @param canvas
 */
private void drawScale(Canvas canvas) {
    mPaint.setStyle(Paint.Style.FILL);
    canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 8, mPaint);
}
效果圖:

但是我們要畫類似這種圖:

 

一起要畫12個這個線,那就相當於每二根線之間的角度就是360/12=30度

 

每換完一根線後畫布就旋轉30度

 

/**
 * 繪制刻度
 * @param canvas
 */
private void drawScale(Canvas canvas) {
    mPaint.setStyle(Paint.Style.FILL);
    for(int i=0;i<12;i++){
        if(i%3==0){//  12  3  6  9對應的線長點
            canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 15, mPaint);
        }else{
            canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 8, mPaint);
        }
        canvas.rotate(30, widhth / 2, widhth / 2);
    }
}
效果:

刻度就是利用了canvas的rotate()旋轉方法繪制上去的,但是得以圓的中心點為旋轉點

第三步繪制時 分 表 表針

這個繪制是根據當前的時間來指向的,

 

/**
 * 繪制時  分 表 指針
 * @param canvas
 */
private void drawPointer(Canvas canvas) {
    mCalendar = Calendar.getInstance();
    mHour = mCalendar.get(Calendar.HOUR);
    mMinuate = mCalendar.get(Calendar.MINUTE);
    mSecond = mCalendar.get(Calendar.SECOND);
    //小時的旋轉度
    mDegrees = mHour*30+mMinuate/2;
    mPaint.setColor(Color.BLACK);
    canvas.save();
    canvas.rotate(mDegrees, widhth / 2, widhth / 2);
    canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint);
    canvas.restore();
    //分鐘
    mPaint.setColor(Color.RED);
    mDegrees = mMinuate*6+mSecond/10;
    canvas.save();
    canvas.rotate(mDegrees, widhth / 2, widhth / 2);
    canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint);
    canvas.restore();
    //繪制表針
    mPaint.setColor(Color.BLUE);
    mDegrees = mSecond*6;
    canvas.save();
    canvas.rotate(mDegrees, widhth / 2, widhth / 2);
    canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint);
    canvas.restore();
}

在這解釋下這個mDegrees這個值 比如現在是21:20 但是分為12小時制的話就是9:20 時就是9*30度=270度 但是這個時針指向9肯定是不對的,因為還有20分鐘呢?時針線肯定是在9和10之間指向,這麼這1小時之間是30度,就拿21:30這個時間來算,這個時候時針角度應該是30*9+30/2=285度 這就說明60分鐘1小時 而1小時是30度,也就是說每2分鐘時針角度應該動一下,根據這個原理分鐘和表之間的計算也是類似的,

還有一點要特別的注意2就是繪制完時針它是根據當前的時針數比如9然後旋轉30*9的 但是canvas使用了動畫完以後一定要恢復到原來的,不然你繪制分鐘就會出問題,我就遇到了這個問題,在這特別提醒下

特別改動下了:類全部代碼復制下看下效果:

 

package com.example.clockview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.ImageView;

import java.util.Calendar;

/**
 * Created by Adminis on 2016/11/6.
 */
public class ClockView extends ImageView {
    private static final String TAG = "ClockView";
    private Paint mPaint;
    private int widhth = 200;//控件的寬度
    private int height = 200;//控件的高度
    private int padding = 5;
    private Calendar mCalendar;
    private int mHour;//小時
    private int mMinuate;//分鐘
    private int mSecond;//秒
    private float mDegrees ;//因為圓是360度 我們有12個刻度 所以就是360/12
    private int mHourLineLen;//時指針 線
    private int mMinuateLine;//分鐘 線
    private int mSecondLine ;//表鐘線
    public ClockView(Context context) {
        this(context, null);
    }
    public ClockView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widhth, height);
        mHourLineLen = (int) (widhth/2*0.6);
        mMinuateLine = (int) (widhth/2*0.7);
        mSecondLine = (int) (widhth/2*0.8);
    }
    private void initPaint() {
        mPaint = new Paint();
        mPaint.setStrokeWidth(3);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.parseColor("#666666"));
        mPaint.setAntiAlias(true);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        drawCircle(canvas);
        drawScale(canvas);
        canvasCenterCircle(canvas);
        drawPointer(canvas);
    }

    /**
     * 在 圓中心繪制一個點
     * @param canvas
     */
    private void canvasCenterCircle(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(widhth / 2, height / 2, 5, mPaint);
    }


    /**
     * 繪制圓
     * @param canvas
     */
    private void drawCircle(Canvas canvas) {
         mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(widhth / 2, height / 2, widhth / 2 - padding, mPaint);
    }
    /**
     * 繪制刻度
     * @param canvas
     */
    private void drawScale(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);
        for(int i=0;i<12;i++){
            if(i%3==0){//  12  3  6  9對應的線長點
                canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 15, mPaint);
            }else{
                canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 8, mPaint);
            }
            canvas.rotate(30, widhth / 2, widhth / 2);
        }
    }
    /**
     * 繪制時  分 表 指針
     * @param canvas
     */
    private void drawPointer(Canvas canvas) {
        mCalendar = Calendar.getInstance();
        mHour = mCalendar.get(Calendar.HOUR);
        mMinuate = mCalendar.get(Calendar.MINUTE);
        mSecond = mCalendar.get(Calendar.SECOND);
        //小時的旋轉度
        mDegrees = mHour*30+mMinuate/2;
        mPaint.setColor(Color.BLACK);
        canvas.save();
        canvas.rotate(mDegrees, widhth / 2, widhth / 2);
        canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint);
        canvas.restore();
        //分鐘
        mPaint.setColor(Color.parseColor("#666666"));
        mPaint.setStrokeWidth(5);
        mDegrees = mMinuate*6+mSecond/10;
        canvas.save();
        canvas.rotate(mDegrees, widhth / 2, widhth / 2);
        canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mMinuateLine, mPaint);
        canvas.restore();
        //繪制表針
        mPaint.setStrokeWidth(2);
        mPaint.setColor(Color.parseColor("#666666"));
        mDegrees = mSecond*6;
        canvas.save();
        canvas.rotate(mDegrees, widhth / 2, widhth / 2);
        canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mSecondLine, mPaint);
        canvas.restore();
    }
}

第四步就是繪制當前時間文字顯示在中心點下面:

 

/**
 * 繪制文字
 * @param canvas
 */
private void drawStr(Canvas canvas) {
    mPaint.setTextSize(24);
    StringBuffer sb =  new StringBuffer();
    if(mHour<10){
        sb.append("0").append(String.valueOf(mHour)).append(":");
    }else{
        sb.append(String.valueOf(mHour)).append(":");
    }
    if(mMinuate<10){
        sb.append("0").append(String.valueOf(mMinuate)).append(":");
    }else{
        sb.append(String.valueOf(mMinuate)).append(":");
    }
    if(mSecond<10){
        sb.append("0").append(String.valueOf(mSecond));
    }else{
        sb.append(String.valueOf(mSecond));
    }
    String str = sb.toString();
    int strW = (int) mPaint.measureText(str);
    canvas.drawText(str, widhth / 2 - strW / 2, widhth / 2 + 30,mPaint);
}

最後一步就是利用Handler每秒去刷新界面就能做到動態的顯示時間了:

最後完整的代碼:

 

package com.example.clockview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.widget.ImageView;
import java.util.Calendar;
/**
 * Created by Adminis on 2016/11/6.
 */
public class ClockView extends ImageView {
    private static final String TAG = "ClockView";
    private Paint mPaint;
    private int widhth = 200;//控件的寬度
    private int height = 200;//控件的高度
    private int padding = 5;
    private Calendar mCalendar;
    private int mHour;//小時
    private int mMinuate;//分鐘
    private int mSecond;//秒
    private float mDegrees ;//因為圓是360度 我們有12個刻度 所以就是360/12
    private int mHourLineLen;//時指針 線
    private int mMinuateLine;//分鐘 線
    private int mSecondLine ;//表鐘線
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            invalidate();
        }
    };
    public ClockView(Context context) {
        this(context, null);
    }
    public ClockView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widhth, height);
        mHourLineLen = (int) (widhth/2*0.6);
        mMinuateLine = (int) (widhth/2*0.7);
        mSecondLine = (int) (widhth/2*0.8);
    }
    private void initPaint() {
        mPaint = new Paint();
        mPaint.setStrokeWidth(3);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.parseColor("#666666"));
        mPaint.setAntiAlias(true);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        drawCircle(canvas);
        drawScale(canvas);
        canvasCenterCircle(canvas);
        drawPointer(canvas);
        drawStr(canvas);
        mHandler.sendEmptyMessage(1);
    }
    /**
     * 繪制文字
     * @param canvas
     */
    private void drawStr(Canvas canvas) {
        mPaint.setTextSize(24);
        StringBuffer sb =  new StringBuffer();
        if(mHour<10){
            sb.append("0").append(String.valueOf(mHour)).append(":");
        }else{
            sb.append(String.valueOf(mHour)).append(":");
        }
        if(mMinuate<10){
            sb.append("0").append(String.valueOf(mMinuate)).append(":");
        }else{
            sb.append(String.valueOf(mMinuate)).append(":");
        }
        if(mSecond<10){
            sb.append("0").append(String.valueOf(mSecond));
        }else{
            sb.append(String.valueOf(mSecond));
        }
        String str = sb.toString();
        int strW = (int) mPaint.measureText(str);
        canvas.drawText(str, widhth / 2 - strW / 2, widhth / 2 + 30,mPaint);
    }
    /**
     * 在 圓中心繪制一個點
     * @param canvas
     */
    private void canvasCenterCircle(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(widhth / 2, height / 2, 5, mPaint);
    }


    /**
     * 繪制圓
     * @param canvas
     */
    private void drawCircle(Canvas canvas) {
         mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(widhth / 2, height / 2, widhth / 2 - padding, mPaint);
    }
    /**
     * 繪制刻度
     * @param canvas
     */
    private void drawScale(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);
        for(int i=0;i<12;i++) {
            if (i % 3 == 0) {//  12  3  6  9對應的線長點
                canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 15, mPaint);
            }else{
                canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 8, mPaint);
            }
            canvas.rotate(30, widhth / 2, widhth / 2);
        }
    }

    /**
     * 繪制時  分 表 指針
     * @param canvas
     */
    private void drawPointer(Canvas canvas) {
        mCalendar = Calendar.getInstance();
        mHour = mCalendar.get(Calendar.HOUR);
        mMinuate = mCalendar.get(Calendar.MINUTE);
        mSecond = mCalendar.get(Calendar.SECOND);
        //小時的旋轉度
        mDegrees = mHour*30+mMinuate/2;
        mPaint.setColor(Color.BLACK);
        canvas.save();
        canvas.rotate(mDegrees, widhth / 2, widhth / 2);
        canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint);
        canvas.restore();
        //分鐘
        mPaint.setColor(Color.parseColor("#666666"));
        mPaint.setStrokeWidth(5);
        mDegrees = mMinuate*6+mSecond/10;
        canvas.save();
        canvas.rotate(mDegrees, widhth / 2, widhth / 2);
        canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mMinuateLine, mPaint);
        canvas.restore();
        //繪制表針
        mPaint.setStrokeWidth(2);
        mPaint.setColor(Color.parseColor("#666666"));
        mDegrees = mSecond*6;
        canvas.save();
        canvas.rotate(mDegrees, widhth / 2, widhth / 2);
        canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mSecondLine, mPaint);
        canvas.restore();
    }
}

終於寫完了!

 

剛群裡有人反映說3時和15秒時時針和表針線不重合的問題,於是我自己寫死了一個數據 測試了下發現真的是有這個bug 導致這個bug造成的原因是

 


/**  * 繪制刻度  * @param canvas  */ private void drawScale(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); for(int i=0;i<12;i++) { if (i % 3 == 0) {// 12 3 6 9對應的線長點 canvas.drawLine(widhth / 2-padding , padding, widhth / 2 -padding, padding + 4 + 15, mPaint); }else{ canvas.drawLine(widhth / 2-padding , padding, widhth / 2-padding, padding + 4 + 8, mPaint); } canvas.rotate(30, widhth / 2, widhth / 2); } }
是這個x軸開始和結束點的坐標不對,應該把-padding去掉就正常了

 

改成後:

 

/**
 * 繪制刻度
 * @param canvas
 */
private void drawScale(Canvas canvas) {
    mPaint.setStyle(Paint.Style.FILL);
    for(int i=0;i<12;i++) {
        if (i % 3 == 0) {//  12  3  6  9對應的線長點
            canvas.drawLine(widhth / 2-padding , padding, widhth / 2 -padding, padding + 4 + 15, mPaint);
        }else{
            canvas.drawLine(widhth / 2-padding , padding, widhth / 2-padding, padding + 4 + 8, mPaint);
        }
        canvas.rotate(30, widhth / 2, widhth / 2);
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved