先上个效果图看下,按住加速按钮不放,实现指针移动,并显示当前的数值
松开手指,暂停加速。
思路:
1.画个圆弧
2.画100个小刻度
3.画20个5分隔的中间刻度
4.画10个小刻度
5.画指针
6.画刻度文字,当前刻度文字
7.实现动态指针变换
开始coding吧。
1.画圆弧
canvas提供的画弧形方法。
确定一个矩形的区域,初始角度,扫过的角度,是否使用中心(true扇形,false弧形),画笔
ok,我们先来确定一下这个矩形怎么放置
定义几个参数
控件的宽高,圆形的半径,
我们在onSizeChanged里面先来定义这个矩形
矩形确定好了,那么就去画弧吧。
可是弧形有角度呢,怎么算呢
这里我们可以这样来思考
我们可以设定一个初始的Angle,
那么按照View的坐标系,初始角度就是90°+(Angle / 2)
扫过的角度就是 360 - Angle
我们实验一下,这里我设置初始Angle 为120
private static final int ANGLE = 120;
mStartAngle = 90 + ANGLE / 2;
mSweepAngle = 360 - ANGLE;
在onDraw中绘制
当然画笔也是需要提前设定的
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(Utils.dp2px(2));
canvas.drawArc(mArcRectF, mStartAngle, mSweepAngle, false, mPaint);
还不错哦。符合预期效果
接下来画格子吧
来介绍个类,PathDashPathEffect
构造的内容shape为一个path对象,可以理解为我们要画的一个小线段的内容
advance表示间隙
phase表示第一个位置预留的空间
关于间隙,可以用PathMeasure去获取我们之前添加的弧形,通过getLenght方法获得弧形的长度
mArcPath.addArc(mArcRectF, mStartAngle, mSweepAngle);
mPathMeasure = new PathMeasure(mArcPath, false);
float length = mPathMeasure.getLength();
有了长度,我们就可以根据要划分的个数来计算间隙了
但是这里有个小提示
我们没一个shape都是有宽度的,所以总体计算的长度,要减去一个shape的宽度
ok,我们先new出来
因为我们要划分100个小单元,所以这里的number是100
float v = length - Utils.dp2px(2);
shape = new Path();
shape.addRect(new RectF(0, 0, Utils.dp2px(2), Utils.dp2px(10)), Path.Direction.CW);
float advance = v / number;
float phase = 0;
mPathDashPathEffect = new PathDashPathEffect(shape, advance, phase, PathDashPathEffect.Style.ROTATE);
接着在ondraw中通过paint设置进来
看下效果,还可以哈
接下来就以此类推,画出20个5分段的小个子
稍微区分一下,将shape调整长一点,画笔也还是利用之前画100个小段的,毕竟颜色都一直,仅仅是长度不一样
然后再来画10分段的长格子,这里用一个新的画笔,颜色设置为黑色进行区分
初具规模了,
继续,画文字
画文字的方法呢,比较简单,但是计算起来确实还是有点小繁琐
你需要确定你的文字坐标,即一个xy位置,
那么我们想精确的在刻度上显示这个文字怎么去获取刻度对应的坐标呢
当然是sin 和cos了
还是这张图,假设我想知道绿色线条终点的xy坐标,怎么算呢
x坐标就是这条线段的长度 * cos(弧度)
y坐标同理,就是长度 * sin(弧度)
我们先写一个简单的方法,来获取刻度上对应的角度的方法
简单想一下,假设现在的刻度是100,那么最终算的的结果就是150+240=390,超出360的减去360,那么就是30度
接下来画文字其实就是for一个循环,每10个刻度画一个文字
但是有个注意事项,文字是有高度的,所以想要文字看上去居中,我们要进行一些计算
获取文字的最顶部位置和最底部位置 ,进行相加 / 2,就是文字在Y轴上的偏移量了,再绘制时讲这个偏移减去即可
文字部分呢,我们也新定义一个画笔
不要忘记加入相对位置
文字是相对于这个圆弧的中心的
运行下看看
剩下的画实时速度的文字其实就很简单了
Y方向,再中心位置向下偏移1/4个半径的长度,看着还算ok
具体的画笔代码就不贴了,就是居中啊,文字大小啊,文字颜色之类的了
画指针
既然前面都已经知道怎么去算文字的位置了,那么指针的中心其实就是圆心了,那么终点坐标就很好计算了。
我们设置一个value,看看是否对应的上
private float mValue = 66;
符合预期
剩下的就是去动态的设置数值,核心就是改变value值,重绘
首先实现Runnable接口
重写run方法
定义一个标识,如果start = true,就不停的加加value
重绘页面
调用postInvalidate
为了不至于过快,再稍微延迟个50毫秒
最后就是到Activity中find出来这个View
new Thread(view) .start
好么?其实也可以
我们来试试看
线性布局,底部放一个button
设置button的touchListener 返回true,按下时,启动线程,手指抬起时,终止线程
实际效果跟效果图一样,不演示了
之前我们在run方法里打印了线程的信息,其实也可以很只管的理解,毕竟每次都是在ontouch里面new 出一个线程吗
这样我们可不喜欢,所以优化一下吧。
线程池
通过改变标记位就可以了
打印出来的线程信息
当然其实也可以用之前的Thread start 方法,但是当手指抬起时,我们是要中断线程,或者说是暂停线程
要么interrupt,要么wait,
那么下次手指再次按下的时候,就需要去恢复线程,就不能使用start,否则会提示Thread is already start,
或者我们也可以用标识,第一次按下的时候,去start,后续按下仅仅改变标识位置也可以
像这样,效果也是一样的
记得在Activity 销毁的时候终止线程哦
Thread 调用interrupt方法终止
Executors 调用shutdownNow
O了,就这样吧,好久...........(*N) 没写博客了,感觉就像流水账一样。
但大体思路应该表述清楚了吧???
用sketch画图好好玩哦