Android自定义组件-绘制时钟

版权所有,禁止匿名转载;禁止商业使用。

1、效果图


Android开发,自定义组件

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>


0 0