导语
这里展示的View估计项目中多半是用不到的,只是用来加深理解的。文章末尾会有全部的代码,如果想研究可以复制过去直接运行,不需要额外的资源。
先看效果:
这里指针是通过手指来改变方向的,并不能通过数字参数来改变,如果需要,可以更改相应的代码。
需要的数学知识
理论的涉及也非常简单,如下所示:
- 在坐标系中,一个点与原点连线与X轴的正切值 tan = 点的纵坐标 ÷ 点的横坐标
- 在每一个象限中,正切函数是单调函数;如图所示:
绘制流程
绘制由线段组成的圆弧
利用线段的旋转来绘图
绘制上图有多种方法,首先介绍一种简单的方法:
将线段旋转多个角度,这样可以绘制出一个圆弧型:
private int width;
private int height;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(width / 2, height / 2);
Paint mPaint = new Paint();
mPaint.setStrokeWidth(5);
for (int i = 0; i <= 360; i += 5) { // 绘制圆形之间的连接线
canvas.drawLine(0, 120, 0, 200, mPaint);
canvas.rotate(10);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
}
上述代码的执行效果:
虽然丑了点,但可以说明问题。不过这样做,我们缺乏对弧形的控制。例如:如何实现圆弧呢?是不是要手动计算起始坐标,旋转的角度,扫过的角度等各种各样的问题?因为怕麻烦,这个方案就被我华丽的抛弃了。
利用两个同心圆来绘制
思路:
- 从圆心发射一条射线出来,与两个圆相交于点A和点B,链接A与B,就可以划出一条我们想要的线段。
- 均匀的发射多条射线,我们就可以得到一个由线段组成的圆弧。
- 如果两个圆圈是圆弧的话,就可以达到我们所要的效果
所以,最终确定的步骤为:
- 画一个大圆弧
- 画一个缩小版的小圆弧
- 均匀地在两个圆弧之间画线段
用动态图来展示下:
相关代码比较多,在文章末尾已经贴出来了(88-172行,代码中有后续的细节处理,需要甄别下相关的代码),这里只是写下思路,不再重复贴代码了
画个一个长度固定、原点确定,方向随着手指变化的指针
这步要实现的效果如上图所示
假设,之前的指针为OZ,现在我们用手指触摸了点A,这时我们希望指针变为OB,那么,该如何实现呢?
- 获取A点的坐标(通过onTouchEvent()可以获取到)
- 画取线段OA(O点为(0,0),所以可以画取)
- 通过测量OA,可以利用PathMeasure.getPosTan()来获取B点的坐标(指针的长度是固定的)
- 在Cavas中画OB线段
如果我们触摸点为X,距离过短怎么办呢?
- 链接OX,并用MeasurePath来测量OX的长度,以及X的坐标(a,b)
- 计算OY与OX的比例 R = OY ÷ OX
- 计算Y点的坐标 x = a × R, y = b × R
- 在Cavas中画OY线段
相关代码同样比较多,在文章末尾已经贴出来了(179-242行,代码中有后续的细节处理,需要甄别下相关的代码),这里只是写下思路,不再重复贴代码了
处理越界的情况
上图情况是我们不想看到。如果指针偏到最右边,就不能再往下偏了;左边同理。这个时候,就需要想到tan函数的性质:
在每一个象限中,正切函数是单调函数
说明下:
- 在第二象限中,当前的tan值小于边界OA的tan值a时,说明此时是在边界外面;如果大于a,说明在边界里面
- 在第一象限中,当前的tan值大于OB的tan值b时,说明在边界外面;如果小于b,说明在边界里面