自定义组件-绘制时钟

1、效果图


2、Canvas对象详解

1.translate(x,y):平移,将画布的坐标原点向左右方向移动x,向上下方向移动y.canvas的默认位置是在(0,0).

  例子:画布原点假如落在(1,1),那么translate(10,10)就是在原点(1,1)基础上分别在x轴、y轴移动10,则原点变为(11,11)。
2.scale(x,y):扩大。x为水平方向的放大倍数,y为竖直方向的放大倍数。
3.rotate(angel):旋转.angle指旋转的角度,顺时针旋转。
4.transform():切变。所谓切变,其实就是把图像的顶部或底部推到一边。
5 save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。
6 restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。save和restore要配对使用(restore可以比save少,但不能多),如果restore调用次数比save多,会引发Error。
7、drawTextOnPath 在指定的path上面绘制文字。
3、代码
package com.example.canvastest.view;

import java.util.Calendar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.example.canvastest.DensityUtil;
import com.example.canvastest.R;

/**
 * 绘制时钟
 * 
 * @author libin
 * 
 */
public class ClockView extends View {
    // 半径
    private float radius = 200;
    private Paint mDownPaint;
    // 宽度
    private float mCirclePaintWidth = 10;
     
    // 上面圆圈的画笔
    private Paint mOutSidePaint;
    // 画文字
    private Paint mTextPaint;

    // 文字大小
    private int textFontSize = 16;
    
    private int longLine ;
    private int shortLine;
    private int widthLine ;
    //小圆心的半径
    private int circle;
    
    private int hourDegrees;
    private int minDegrees;
    private int secDegrees;
     

    public ClockView(Context context) {
        super(context);
        init();
    }

    public ClockView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mDownPaint = new Paint();
        mDownPaint.setColor(Color.BLACK);
        mDownPaint.setAntiAlias(true);
        mDownPaint.setStrokeWidth(mCirclePaintWidth);

        textFontSize = (int) getResources().getDimension(R.dimen.textSize);
        shortLine = (int) getResources().getDimension(R.dimen.shortLine);
        longLine = (int) getResources().getDimension(R.dimen.longLine);
        widthLine = (int) getResources().getDimension(R.dimen.widthLine);
        radius = (int) getResources().getDimension(R.dimen.circleRadius);
        circle = (int) getResources().getDimension(R.dimen.circle);
        // 上面的画笔
        mOutSidePaint = new Paint();
        mOutSidePaint.setAntiAlias(true);
        mOutSidePaint.setStrokeWidth(mCirclePaintWidth);
        mOutSidePaint.setStyle(Style.STROKE);
        mOutSidePaint.setColor(Color.BLACK);
        // 上面的画笔
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(Color.BLACK);
        mTextPaint.setStrokeWidth(widthLine);
        mTextPaint.setTextAlign(Align.CENTER);
        
        mTextPaint.setTextSize(textFontSize);
        mDownPaint.setTextSize(textFontSize);
        
        mHandler.sendEmptyMessage(10);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        
        // 平移,将画布的坐标原点向左右方向移动x,向上下方向移动y.canvas的默认位置是在(0,0).
        // 例子:画布原点假如落在(1,1),那么translate(10,10)就是在原点
        // (1,1)基础上分别在x轴、y轴移动10,则原点变为(11,11)。
        canvas.translate(canvas.getWidth() / 2, canvas.getHeight() / 2); // 将位置移动画纸的坐标点:150,150
        // 画圆
        canvas.drawCircle(0, 0, radius, mOutSidePaint);
        canvas.save();

        // 绘制路径
        Path path = new Path();
        path.addArc(new RectF(-radius, -radius, radius, radius), -180, 180);
        mDownPaint.setTextAlign(Align.CENTER);

        int pathy = DensityUtil.dip2px(getContext(), -5);
        // 让文字显示到中间
        canvas.drawTextOnPath("canvas绘制钟表", path, 0, pathy, mDownPaint);
        canvas.restore();

        //绘制刻度
        canvas.save();
        canvas.rotate(210);
        float y = radius;
        int count = 60; // 总刻度数
        for (int i = 0; i < count; i++) {
            if (i % 5 == 0) {
                canvas.drawLine(0f, y-longLine+2, 0, y+mCirclePaintWidth/2 , mTextPaint);
                canvas.drawText(String.valueOf(i / 5 + 1), 0, y -mCirclePaintWidth/2-longLine, mTextPaint);

            } else {
                canvas.drawLine(0f, y  - shortLine , 0f,y-mCirclePaintWidth/2, mTextPaint);
            }
            canvas.rotate(360 / count, 0f, 0f); // 旋转画纸
        }
        canvas.restore();
     
        
        //绘制秒针
        canvas.save();
        canvas.rotate(secDegrees);
        Paint hourPaint = new Paint(mDownPaint);
        hourPaint.setColor(Color.BLACK);
        hourPaint.setStrokeWidth(circle);
         
        canvas.drawLine(0, -longLine, 0, radius*2/3, hourPaint);
        canvas.restore();
        
        //绘制分针
        canvas.save();
        canvas.rotate(minDegrees);
        canvas.drawLine(0, -longLine, 0, radius*1/2, hourPaint);
        canvas.restore();
    
        //绘制时针
        canvas.save();
        canvas.rotate(hourDegrees);
        canvas.drawLine(0, -longLine, 0, radius*1/3, hourPaint);
        canvas.restore();

        //绘制中心黑点
        Paint tmpPaint = new Paint(mDownPaint);
        tmpPaint.setColor(Color.BLACK);
        canvas.drawCircle(0, 0, circle*2, tmpPaint);
         
         
        //绘制中心红点
        tmpPaint.setColor(Color.RED);
        canvas.drawCircle(0, 0, circle*4/3, tmpPaint);
        super.onDraw(canvas);
    }
 
    /**
     * 获取角度
     */
    private void calculate(){
        Calendar calendar = Calendar.getInstance();
        int hour = calendar.get(Calendar.HOUR);
        if (hour>12) {
            hour = hour-12;
        }
        hourDegrees = hour*30-180;
        
        int min = calendar.get(Calendar.MINUTE);
        minDegrees = min * 6-180;
        
        int sec = calendar.get(Calendar.SECOND);
        secDegrees = sec * 6-180;
        Log.i("tag", " "+ hour+" "+min+" "+sec);
    }
    
    /**
     * 定时器
     */
    private Handler mHandler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case 10:
                calculate();
                invalidate();
                this.sendEmptyMessageDelayed(10, 1000);
                break;
            default:
                break;
            }
        };
    };
}
4、常量数据
 <dimen name="textSize">14sp</dimen>
    <dimen name="circleRadius">100dip</dimen>
    <dimen name="shortLine">9dip</dimen>
    <dimen name="longLine">15dip</dimen>
    <dimen name="widthLine">5dip</dimen>
    <dimen name="circle">3dip</dimen>



原文地址:https://www.cnblogs.com/lbangel/p/4335850.html