关于 ClipPath
我们应该都使用过 ClipXXX
相关的组件, 来实现一些 圆角矩形/圆形形状十分的方便,那如果想要实现一些奇形怪状的 Widget,例如 五角星/圆弧形之类的,那就只能用 ClipPath
了。
想要了解 ClipPath
,还是直接去官网撸文档,介绍如下:
A widget that clips its child using a path.
Calls a callback on a delegate whenever the widget is to be painted. The callback returns a path and the widget prevents the child from painting outside the path.
Clipping to a path is expensive.
用 path 来剪切 child 的 widget。
每当要绘制小部件时,都会在委托上调用回调。回调函数返回一个路径,并且该 widget 可防止 child 在 path 外绘制。
裁剪 path 很昂贵。
总的来说,也就是按照路径来剪切子 widget,但是裁剪 path 很昂贵。
关于如何使用,我们还是先来看一下他的构造函数:
const ClipPath({
Key key,
this.clipper, // final CustomClipper<Path> clipper;
this.clipBehavior = Clip.antiAlias,
Widget child,
}) : assert(clipBehavior != null),
super(key: key, child: child);
首先可以看到需要的参数其实就两个,一个是 clipper
,另一个是 child
。
child
就是被 clipper
裁剪的组件,具体是啥自己来写就行了,剩下的就是 clipper
。
看一下 clipper
的源码:
/// CustomClipper
abstract class CustomClipper<T> {
/// Creates a custom clipper.
///
/// The clipper will update its clip whenever [reclip] notifies its listeners.
const CustomClipper({ Listenable reclip }) : _reclip = reclip;
final Listenable _reclip;
/// 返回 clip 的说明 -> T
T getClip(Size size);
/// 是否重新 clip
bool shouldReclip(covariant CustomClipper<T> oldClipper);
}
这里去掉了一些方法,只保留了我们需要重写的,其中最主要的就是 T getClip(Size size)
。
在 ClipPath
里传入的泛型为 <Path>
,其实我们熟知的 ClipRect
/ ClipRRect
/ ClipOval
也就是对应着 CustomClipper<Rect>
/ CustomClipper<RRect>
/ CustomClipper<Rect>
而已。
所以在这里我们只需要定义好自己的 Path
就可以实现任意形状的 Widget 了。
我们来实现如下形状(上面是原图、下面是裁剪过的):
综上所述,只需要实现一个 CustomClipper<Path>
然后传入ClipPath
的 clipper
参数即可。
代码如下:
class MyClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
Path path = Path();
// 从 60,0 开始
path.moveTo(60, 0);
// 二阶贝塞尔曲线画弧
path.quadraticBezierTo(0, 0, 0, 60);
// 连接到底部
path.lineTo(0, size.height / 1.2);
// 三阶贝塞尔曲线画弧
path.cubicTo(size.width / 4, size.height, size.width / 4 * 3, size.height / 1.5, size.width, size.height / 1.2);
// 再连接回去
path.lineTo(size.width, 60);
// 再用二阶贝塞尔曲线画弧
path.quadraticBezierTo(size.width - 60, 60, size.width - 60, 0);
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
逻辑就不说啦,都在注释里。
因为ClipPath
的消耗比较大,所以如果只是想裁剪个圆角之类的,还是推荐使用自带的 ClipRRect
之类的,他们的性能更好(官方文档所说)。
ClipPath
还有一个静态方法 ClipPath.shape()
,这个具体就不说了,有感兴趣的可以去翻源码查看。
Copyright© 2013-2019