写于 2015 年 11 月 16 日

具体的实现

  • 首先偏移量
  • 然后是计算贝塞尔曲线
  • 接下来就是计算控制点o,p
    看到 QQ 拖动删除小红点的动画效果,就想着做个类似的效果,没找到Android 版的教程,于是就自己撸了一个,代码地址:https://github.com/flyer88/JellyCircle/tree/master/circleindicator ,该栗子的实现在circleIndicator包中,app包下是另一个demo,还没写好。
img
img
img

注意:为实现上面链接中所示的动画,首先确定,两个圆随着偏移量的改变,半径大小出现了变化,同时贝塞尔曲线有所变化,那剩下的问题就是如何改变两个圆的半径大小,圆的位置,同时计算和绘制贝塞尔曲线

接下来看具体的实现

首先偏移量

我此处给的值比较简单,直接通过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两点的位置)

img

其中,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代码