用贝塞尔曲线画画(二)

342 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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)。