携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
Android中的应用
贝塞尔曲线在Android中的应用主要表现在自定义View和动画上,理论上你可以利用贝塞尔曲线得到任何你想要的路径,除了圆形,但可以通过二阶、三阶贝塞尔曲线来拟合圆,具体算法可参考这篇文章Approximate a circle with cubic Bézier curves。
Android提供的API
Android中的Path类也封装了二阶及三阶贝塞尔曲线函数。可以输入控制点、起始点、结束点来绘制相应的贝塞尔曲线。
public void quadTo(float x1, float y1, float x2, float y2) {
isSimplePath = false;
nQuadTo(mNativePath, x1, y1, x2, y2);
}
public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
isSimplePath = false;
nRQuadTo(mNativePath, dx1, dy1, dx2, dy2);
}
public void cubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
isSimplePath = false;
nCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
}
public void rCubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
isSimplePath = false;
nRCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
}
quadTo()
二阶贝塞尔曲线,其中(x1,y1)是控制点的坐标,(x2,y2)是结束点的坐标,起始点是通过path.moveTo()来控制的,如果没有调用,则默认控件左上角(0,0)为起始点。然后下个点的起始点是本次的结束点。
rQuadTo()
也是二阶贝塞尔函数,只不过其中的(dx1,dy1)是相对于上次终点坐标值的改变量,比如上次终点坐标(100,200),调用path.rQuadTo(100,-200,100,200),效果就是以(100,200)为起始点,(200,0)为控制点,(200,400)为终点画一条二阶贝塞尔曲线。
cubicTo()和rCubicTo()
cubicTo()是三阶贝塞尔曲线,同样通过path.moveTo()设置起始点,(x1,y1)为1号控制点,(x2,y2)为2号控制点,(x3,y3)为结束点。rCubicTo()同样也是使用相对坐标。
LodingView
左右两边的小球运动路径就是自定义的二阶贝塞尔曲线,通过设置一个属性动画得到一个从0到1变化的值,再根据二阶贝塞尔函数公式动态计算出小球坐标,canvas中再不断绘制小球。
val valueAnimation = ValueAnimator.ofFloat(0f,1f)
valueAnimation.interpolator = LinearInterpolator()
valueAnimation.duration = 500L
valueAnimation.repeatCount = ValueAnimator.INFINITE
valueAnimation.repeatMode = ValueAnimator.REVERSE
valueAnimation.addUpdateListener {
val t = it.animatedValue as Float
showPoint1 = secondBessel(t,startPoint1,controlPoint1,endPoint1)
postInvalidate()
}
/**
* @param t
* @param startPoint 起始点
* @param controlPoint 控制点
* @param endPoint 结束点
* 二阶贝塞尔函数
*/
private fun secondBessel(t:Float,startPoint: PointF,controlPoint: PointF,endPoint: PointF):PointF{
val pointF = PointF()
val tem =1-t
pointF.x = startPoint.x*tem*tem+2*t*tem*controlPoint.x+t*t*endPoint.x
pointF.y = startPoint.y*tem*tem+2*t*tem*controlPoint.y+t*t*endPoint.y
return pointF
}
然后再通过AnimatorSet()调一调左右两个小球动画的播放顺序就行了。
DEMO源码
做一个炫酷的入场动画
这是我毕设项目的Splash界面,原理和LoadingView一样,这里画了五条二阶贝塞尔曲线,并且加了个六边形边长逐渐变大的效果(中间那个button点击效果不是我做的,用的是ShineButton)。