前言
说到贝塞尔曲线各位前端的小伙伴一定不陌生😆,贝塞尔曲线是一段优美的曲线,他可以极大程度的提高我们程序的美观性,试想我们的应用如果只有简单的矩形、圆形、三角形巴拉巴拉的基础图形,很难达到我们期望的良好的交互效果。我们如何去随性所欲的裁切、遮盖、绘制我们想要的界面的,今天的主角——贝塞尔曲线,必不可少👀。
贝塞尔曲线🔮
开门见山,要学会贝塞尔曲线,肯定必须要了解,什么是贝塞尔曲线啊。不知道有没有小伙伴和我一样,一开始有被这个名字吓到🙀,第一感觉就是:高端,复杂,难搞。所以别慌,接下来它不叫贝塞尔了,我就叫他:简单曲线!📈
OK,不搞大家心态了😉,其实没有难学的技术,只怕肯钻研的开发。给大家揭开它的神秘面纱了:
- 贝塞尔曲线(
Bezier curve
)是计算机图形学中相当重要的参数曲线,它通过一个方程来描述一条曲线,根据方程的最高阶数,又分为线性贝赛尔曲线,二次贝塞尔曲线、三次贝塞尔曲线和更高阶的贝塞尔曲线。
如上所述,贝塞尔曲线有很多次,二次、三次、四次...,今天主要给各位介绍的是二次的贝塞尔曲线💡。
二次贝塞尔曲线
二次贝塞尔曲线由三个点P0
,P1
,P2
来确定,这些点也被称作控制点。曲线的方程为:
啊?我人裂开了,这人都看傻了呀,写的啥呀🙃?别急,一点一点的来剥离这个公式。首先根据第一句话,我们可以明确的是,公式中的
P0
,P1
,P2
分别代表的是三个点。这个t
呢?这个t
各位可以暂时看作一个从0
到1
之间的一个数。这样整个公式中的各个字符所代表的含义也就明确了🐳。
看图细说(必看🌟):
- 选定一个
0~1
的t
值 - 通过
P0
和P1
计算出点Q0
,Q0
在P0 P1
连成的直线上,并且length( P0, Q0 ) = length( P0, P1 ) * t
- 同样,通过
P1
和P2
计算出Q1
,使得length( P1, Q1 ) = length( P1, P2 ) * t
- 再重复一次这个步骤,通过
Q1
和Q2
计算出B
,使得length( Q0, Q1 ) = length( Q0, B ) * t
。B
就为当前曲线上的点
注:上面的length
表示两点之间的长度。
哎,认真阅读完上面一段,并且理解的同学,应该已经发现,我们通过上面的手段,得到了一个点——点B
。那么,如何由点到线的过渡呢?追本溯源,各位看一下我们最开始的公式,我们一开始就假设了t
是一个常量,但其实不然🤪。这个t
就是我们画出这条曲线的方法。如果将t
的值从0
过渡到1
,不断计算点B
,就可以得到一条二次贝塞尔曲线:
Flutter中的贝塞尔
其实在canvas
中已经有绘制二次贝塞尔曲线,在Flutter
中就是这个方法:
/// Adds a quadratic bezier segment that curves from the current
/// point to the given point (x2,y2), using the control point
/// (x1,y1).
void quadraticBezierTo(double x1, double y1, double x2, double y2) native 'Path_quadraticBezierTo';
复制代码
这个方法中我们传入了看起来是四个坐标?好像很复杂的样子?一点都不复杂🔦,咱们在上文中已经解开了疑惑。其中x1
, y1
, x2
, y2
即为后两个控制点(P1
和P2
)的横纵坐标。那P0
勒?P0
就是你当前所在的位置🏄🏻。说的还是很抽象,来实战吧~
起飞 🛫️
打开DartPad,新建一个Flutter Pad
,我们的第一步就要新建一个Container
,放入我们的主题文字,给上一个背景色,没啥技术含量,我一步带过了~,希望各位跟上🏃。
然后我们要在我们的
Container
外层嵌套一个裁切组件,用于裁切我们这个组件。我们用的组件就是ClipPath
,顾名思义,我们这个组件既然是裁切所用,各位想想,一个裁衣工,在裁剪衣服时依据是什么?🤔是裁衣服的路线呀~,所以我们这个组件中的必要参数:clipper
就是一个自定义的路线罢了。
我们嵌套完成以后,来定义我们的裁切路线咯,首先看到的是两个必须实现的父类方法,一个返回
Path
的方法不用说,肯定是我们的路线,另一个方法shouldReclip
是让我们决定是否需要重新裁切✂️,这不是我们的重点,直接给个true
完事儿。
万事俱备,正式开工咯!我们来新建一个
path
,我们的起点是坐标原点,也就是左上角,我们认为是(0,0)
,然后我们首先到了哪个点呢?
path.lineTo(0, size.height - 80);
复制代码
这是哪个点?是我们从原点直接向下👇走,走到离我们的Container
高度还剩80
处,我们要开始画贝塞尔曲线了!上面就说过,我们要画贝塞尔曲线,我们要传入两个点的坐标!是后面两个点!P1
和P2
,自己定义两个呗。定义好以后我们调用path
自带绘制贝塞尔方法试试🖼。
/// P1
var controllPoint = Offset(50, size.height);
/// P2
var endPoint = Offset(size.width/2, size.height);
/// 绘制贝塞尔曲线
path.quadraticBezierTo(controllPoint.dx, controllPoint.dy, endPoint.dx, endPoint.dy);
复制代码
有人会问,P0
跑哪儿去了,其实不难发现,P0
就是我们最开始走到的那个距离Container
下边界还有80
的点,也就是在贝塞尔中的起点~,来看一下效果图吧~我已经帮各位把点都标注出来了🎉。
看见这美丽的弧度了吗🎆?虽然很普通,但确实是我们的贝塞尔的起源啊,有一个弧度就有一万种弧度🔮!但是好像...我们切的有点多,为啥捏,因为我们的终点🏁就到了
P2
,起点是左上角,这连起来确实是这样~我们只需要把我们未走完的路走完就行了~