本文是 【剪裁 widget】系列的第三篇,也是最后一篇,今天介绍一下ClipOval 和 ClipRRect。
ClipOval 介绍
Flutter ClipOval 用 椭圆形去剪裁 child,path 以外的部分不显示,还能高效的实现动画。
剪裁是在绘制阶段,具体实现是在 paint 方法中调用 PaintingContext 类的 pushClipPath 方法进行剪裁。
void paint(PaintingContext context, Offset offset) { ... layer = context.pushClipPath( needsCompositing, offset, Offset.zero & size, _clip!, super.paint, clipBehavior: clipBehavior, oldLayer: layer as ClipPathLayer?, ); ... } 复制代码
和 ClipPath 一样,调用 PaintingContext 的 pushClipPath。所以从本质上来看, ClipOval 和 ClipPath是一样的,相当于是给 ClipPath 起了一个别名。ClipOval 的唯一价值就是可以增加可读性,而且它会把 Rect 自动转为 Oval path,用起来更方便些。
Path _getClipPath(Rect rect) { if (rect != _cachedRect) { _cachedRect = rect; _cachedPath = Path()..addOval(_cachedRect!); } return _cachedPath; } 复制代码
ClipPath 的参数 clipper 的类型是 CustomClipper,ClipOval 的参数 clipper 的类型是 CustomClipper,所以ClipOval更容易使用。上面代码_getClipPath
的参数 rect 就是 clipper.getClip 返回的 Rect。
ClipOval 的默认效果是把原来的矩形 widget 剪裁成 内切椭圆,如果原来的矩形是正方形,那么剪裁的结果就是一个圆。如果要得到不同的剪裁结果 ,就需要自定义剪裁。
自定义 Oval 剪裁
我们可以指定 clipper 参数进行自定义裁剪。
举个例子,我们想裁剪出花朵的部分。图片大小为 100 x 100。
class MyClipper extends CustomClipper<Rect> { @override Rect getClip(Size size) { return Rect.fromLTWH(20, 10, 65, 65); } @override bool shouldReclip(covariant CustomClipper<Rect> oldClipper) { return false; } } 复制代码
Center( child: ClipOval( clipper: MyClipper(), child: Image.network( 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9eb382cf5d7341938dfbf6fa2442242e~tplv-k3u1fbpfcp-watermark.image?', width: 100, height: 100, ), ), ); 复制代码
和 ClipPath 的 MyClipper 几乎完全一样,就是把类型换成了 Rect。
ClipRRect 介绍
Flutter ClipRRect 用圆角矩形去剪裁 child,path 以外的部分不显示,还能高效的实现动画。
剪裁是在绘制阶段,具体实现是在 paint 方法中调用 PaintingContext 类的 pushClipRRect 方法进行剪裁。只是比 ClipRect 多了一个参数 borderRadius,clipper 的类型不同。
默认情况下 ClipRRect 没有效果的,指定 borderRadius,可以把四角剪裁成圆角,但如果要在不同的位置进行剪裁,需要自定义。
下面通过一个示例演示一下 ClipRRect 自定义剪裁的用法
自定义 RRect 剪裁
class MyClipper extends CustomClipper<RRect> { @override RRect getClip(Size size) { return RRect.fromRectAndRadius(Rect.fromLTWH(20, 10, 65, 65),Radius.circular(21)); } @override bool shouldReclip(covariant CustomClipper<RRect> oldClipper) { return false; } } 复制代码
Center( child: ClipRRect( borderRadius:BorderRadius.all(Radius.circular(21)) , clipper: MyClipper(), child: Image.network( 'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/85a4c49c34434ef3a21dc9458c355866~tplv-k3u1fbpfcp-watermark.image?', width: 100, height: 100, ), ), ) 复制代码
应用场景
Flutter ClipOval 与 Flutter ClipRRect 的应用场景和 ClipRect 是一样的,不再赘述,也是剪裁 widget 和制作动画。在 【剪裁 widget】Flutter ClipRect 一文中对如何写动画有举例。
剪裁 widget 结束语
如果你是按顺序先看第一篇 ClipRect,再看第二篇 ClipPath,然后再看这篇,你会觉得非常轻松。知识是有联系的,找到破入点,然后一网打尽。