1. 从直线到曲线:为什么我们需要贝塞尔曲线?
在Android UI开发中,绘制图形是家常便饭。画直线、矩形、圆形,系统都提供了非常方便的API,比如 Canvas.drawLine 、 drawRect 、 drawCircle 。这些基础图形由简单的数学方程定义,实现起来直观且高效。但是,当需求变成“画一条光滑的、有弧度的曲线”时,比如一个自定义的进度条波浪、一个灵动的下拉刷新动画、或者一个圆润的图标轮廓,很多开发者就开始头疼了。你可能会想,那我用 drawArc 画一段圆弧拼接?或者用很多很短的直线段去模拟?前者不够灵活(只能画标准圆弧),后者则既不优雅,性能也堪忧,而且拼接处会有明显的棱角。
这就是贝塞尔曲线(Bézier curve)登场的时候了。它本质上是一种参数曲线,由若干个“控制点”来定义其形状。你可以把控制点想象成磁铁,曲线会被这些磁铁“吸引”,从而形成光滑的路径。贝塞尔曲线的伟大之处在于,它用一套简洁的数学模型,解决了用少量点定义复杂平滑曲线的难题。在计算机图形学中,它是矢量图形的基石,PostScript、TrueType字体、以及我们熟悉的SVG、Canvas 2D和Android的 Path 类,其背后的曲线核心都是贝塞尔曲线。
在Android里,我们主要通过 Path 类的 quadTo (二阶)和 cubicTo (三阶)方法来使用贝塞尔曲线。理解它们的数学公式,绝不是纸上谈兵。它能让你从“大概调调控制点试试看”的懵懂状态,进化到“我脑子里已经知道移动这个点曲线会怎么变化”的掌控状态。当UI设计师丢给你一个用贝塞尔曲线描绘的复杂图标时,你能精准地还原;当产品经理想要一个弹性回弹动画时,你能用贝塞尔曲线来定义运动轨迹,让动画更加自然。今天,我们就彻底搞懂二阶和三阶贝塞尔曲线,并窥探一下更高阶的奥秘。
2. 二阶贝塞尔曲线:抛物线背后的两个控制点
二阶贝塞尔曲线是最简单也是最常用的曲线之一,它由三个点定义:一个起点(P0)、一个终点(P2),以及一个控制点(P1)。曲线从P0出发,走向P1,最终到达P2,但不会经过P1,P1只起到“牵引”方向的作用。它的形状就像是被P1这个点拉出来的光滑弧线。
2.1 公式推导与几何意义
二阶贝塞尔曲线的公式通常用参数 t 来表示, t 的取值范围是[0, 1]。当 t=0 时,点在起点P0;当 t=1 时,点在终点P2。公式如下:
B(t) = (1-t)² * P0 + 2 * (1-t) * t * P1 + t² * P2
这个公式是怎么来的呢?我们可以从一个经典的几何作图法来理解,这个过程本身也揭示了公式的推导逻辑:
-
在线段上取比例点 :假设我们有线段P0P1和线段P1P2。在每条线段上,我们都取一个点,这个点距离线段起点的比例是
t。我们记P0P1上的点为A,P1P2上的点为B。-
A = P0 + t * (P1 - P0) = (1-t) * P0 + t * P1 -
B = P1 + t * (P2 - P1) = (1-t) * P1 + t * P2这两个公式就是线性插值(Lerp)。
-
-
连接并再次取点 :连接点A和点B,得到新的线段AB。在这条新线段AB上,同样取一个比例为
t的点,记作Q。-
Q = A + t * (B - A) = (1-t) * A + t * B
-
-
得到曲线点 :将A和B的表达式代入Q的公式:
Q = (1-t) * [(1-t)*


3万+

被折叠的 条评论
为什么被折叠?



