android 自定义view实现表盘效果
来源:互联网 发布:python 爬虫 去标签 编辑:程序博客网 时间:2024/04/30 00:38
周末没事在家想干点啥,记得一年多前面试,那公司直接发个面试题让我做,其中就有让我做一个简单的表盘效果,不过当时没做出来,所以也没好意思去面试,今天就实现下,大概分如下几步
第一步:画一个简单的圆
第二步:绘制刻度
第三步:绘制时,分,表指针
第四步:绘制当前时间文字
第五步:实现时间动态显示
第一步画一个圆是很简单的,
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造成的原因是
是这个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); }}
改成后:
/** * 绘制刻度 * @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); }}我现在把时针写死在3点 秒数定在15秒后效果:
谢谢群里提出问题的同学
- android 自定义view实现表盘效果
- Android 自定义View 实现表盘效果
- Android 自定义View 实现表盘效果
- android 自定义 view 实现表盘效果
- Android 自定义view(画表盘)
- Android 自定义View——表盘实例
- 自定义View 手表表盘
- 自定义View-汽车表盘
- Android自定义View及canvas(表盘实例)
- Android笔记自定义View之制作表盘界面
- android 自定义表盘控件
- android自定义表盘
- android 自定义表盘
- android自定义view实现progressbar的效果
- Android 自定义view实现水波纹效果
- Android 自定义View 实现刮刮卡效果
- Android:自定义View实现水波进度效果
- android 自定义view实现水波纹效果
- 10.31 NOIP模拟赛 (afternoon)
- ssh整合(4)Spring与hibernate整合
- (译)LearnOpenGL实际案例Breakout(十):能量块
- 通过自带SSH框架的搭建过程注意和jar包解释
- 233. Number of Digit One
- android 自定义view实现表盘效果
- Linux getpid函数
- 二叉树遍历应用114. Flatten Binary Tree to Linked List
- android graphic(8)—surface申请GraphicBuffer过程
- scanf 和printf 的相关注意事项
- 自苦
- 关于RotateRect的一些说明
- 01 计算机常识
- MetaException(message:Hive metastore database is not initialized. Please use schematool (e.g. ./sch