indicator-01.gif
indicator-02.gif
indicator-03.gif
注意:为实现上面链接中所示的动画,首先确定,两个圆随着偏移量的改变,半径大小出现了变化,同时贝塞尔曲线有所变化,那剩下的问题就是如何改变两个圆的半径大小,圆的位置,同时计算和绘制贝塞尔曲线
接下来看具体的实现#
首先偏移量###
我此处给的值比较简单,直接通过SeekBar来获取偏移量
获取偏移量后,需要改变的数据有,半径大小,以及第二个圆的位置,以及贝塞尔曲线的重新绘制
具体代码如下:
mEndCircle.setX(dpToPx(mDefaultFirstX + mMaxDistance * offset,getResources()));//修改第二个圆的位置
mEndCircle.setRadius(dpToPx(mDefaultMinRadius,getResources()) + offset * dpToPx(mDefaultMaxRadius - mDefaultMinRadius,getResources()));//第二个圆半径变大
mStartCircle.setRadius(dpToPx(mDefaultMaxRadius,getResources()) - offset * dpToPx(mDefaultMaxRadius - mDefaultMinRadius,getResources()));//第一个圆半径变小
mCanDrawBezier = calculatePoint(mStartCircle, mEndCircle);//计算贝塞尔曲线
invalidate();//刷新,触发onDraw(),重新绘制
然后是计算贝塞尔曲线###
看下图,基本上可以确定出有两条曲线,我没有画两条曲线,而是一条mBezierPath搞定
A->B->C->D->A(关于控制点哦o,p后面会有计算分析,基本按照上图中所写就可以计算出o,p两点的位置)
14-51-38.jpg
其中,A点是开始点,直接 moveTo() 即可,然后用lineTo()到B点,再调用系统自带的贝塞尔曲线方法quadTo(ponitP.x,pointP.y)计算即可,然后就是一样的lineTo()到D点,quadTo(pointO.x,pointP.y);
关于quadTo(x1,y1,x2,y2)的使用,可以去百度一下,简单说一下,就是前面两个是控制点,后面两个是到达的点
这样mBezierPath基本就画好了,然后画起始圆和结束圆就可以了(当然,如果考虑到overdraw的话,起始可以用clipRect clipReject去掉重复的半圆,此处偷懒,直接画了两个圆,没有去掉重复绘制,或者直接画一个半圆,当然半圆的效果和圆是不一样的)
以下是构建出mBezierPath的代码
mBezierPath.reset();
mBezierPath.moveTo(mStartA.getX(), mStartA.getY());
mBezierPath.lineTo(mStartB.getX(), mStartB.getY());
mBezierPath.quadTo(mControlPointP.getX(), mControlPointP.getY(), mEndC.getX(), mEndC.getY());
mBezierPath.lineTo(mEndD.getX(), mEndD.getY());
mBezierPath.quadTo(mControlPointO.getX(), mControlPointO.getY(), mStartA.getX(), mStartA.getY());
接下来就是计算控制点o,p
以图二简单的为例子,这种方式比较极端,计算比较容易,两个控制点p,o和H点重合,直接(R1(x,y)+R2(x,y))/2 = H(x,y)
图一也不麻烦,根据图一标注θ也可以算出o,p两点的x,y,具体实现可以看github代码