前言:
这是我参与8月更文挑战的第 17 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战
,我准备在本月挑选 31
个以前没有介绍过的组件,进行全面分析和属性介绍。这些文章将来会作为 Flutter 组件集录
的重要素材。希望可以坚持下去,你的支持将是我最大的动力~
一、认识 PhysicalShape 组件
大家应该没怎么用过 PhysicalShape
,从名字中可以看出它是 Physical
+ Shape
,也就是物理性状。从注释中可以看出,它的作用是将子组件根据路径裁剪,这时你应该会想到 ClipPath 组件。另外可以看出这个裁剪可以具有阴影效果。
1. PhysicalShape 基本信息
下面是 PhysicalShape
组件类的定义
和 构造方法
,可以看出它继承自 SingleChildRenderObjectWidget
。实例化时必须传入 clipper
和 color
参数。
其中 clipper
参数的类型为 CustomClipper<Path>
,这和 ClipPath 中的 clipper
入参一样。
final CustomClipper<Path> clipper;
另外,可以指定影深 elevation
、阴影颜色 shadowColor
、和裁剪行为 clipBehavior
。可见默认情况想是没有影深的,阴影颜色为黑色。
2. PhysicalShape 的使用
对于 CustomClipper<Path>
对象,在 ClipPath 组件 一文中已经详细介绍了,这里不再赘述,可详见之。先看两个必须的入参 clipper
和 color
。如下,通过 CircleBorder
形状裁剪一个圆形,color
即为填充色。
class PhysicalShapeDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return PhysicalShape(
child: SizedBox(
width: 80,
height: 80,
),
clipBehavior: Clip.hardEdge,
clipper: const ShapeBorderClipper(
shape: CircleBorder(),
),
color: Colors.deepPurpleAccent,
);
}
}
PhysicalShape
可以通过 elevation
和 shadowColor
来指定阴影,效果如下:
class PhysicalShapeDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return PhysicalShape(
shadowColor: Colors.blueAccent,
elevation: 3,
child: SizedBox(
width: 80,
height: 80,
),
clipBehavior: Clip.hardEdge,
clipper: const ShapeBorderClipper(
shape: CircleBorder(),
),
color: Colors.deepPurpleAccent,
);
}
}
3.PhysicalShape 自定义形状裁剪
借用 ClipPath 组件 一文中自定义的形状裁剪看一下 PhysicalShape
的效果。如下是三角形裁剪 TriangleClipper
的效果,可以看出也具有阴影效果。
class TriangleClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
print(size);
Path path = Path()
..moveTo(0, size.height)
..relativeLineTo(size.width, 0)
..relativeLineTo(-size.width / 2, -size.height)
..close();
return path;
}
@override
bool shouldReclip(covariant CustomClipper<dynamic> oldClipper) {
return true;
}
}
下面是爱心路径裁剪效果:
class LoveClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
double fate = 18.5*size.height/100;
double width = size.width / 2;
double height = size.height / 4;
Path path = Path();
path.moveTo(width, height);
path.cubicTo(width, height, width + 1.1 * fate, height - 1.5 * fate, width + 2 * fate, height);
path.cubicTo(width + 2 * fate, height, width + 3.5 * fate, height + 2 * fate, width, height + 4 * fate);
path.moveTo(width, height);
path.cubicTo(width, height, width - 1.1 * fate, height - 1.5 * fate, width - 2 * fate, height);
path.cubicTo(width - 2 * fate, height, width - 3.5 * fate, height + 2 * fate, width, height + 4 * fate);
return path;
}
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
return true;
}
}
只要自定义形状,都可以通过 PhysicalShape
组件进行裁剪,并且具有阴影效果,但是这个阴影是固定的,用户无法设置阴影的偏移。另外,这个裁剪和 ClipPath
一样,PhysicalShape
可以裁剪任意组件
。
二、 PhysicalShape 源码简看
它继承自 SingleChildRenderObjectWidget
,会维护 RenderObject
对象。可以看出它通过 RenderPhysicalShape
渲染对象实现功能。其中颜色、裁剪器、阴影等属性都是构建 RenderPhysicalShape
的入参。
在 RenderPhysicalShape#paint
中,开始会进行阴影的绘制。
裁剪器被设置到 PhysicalModelLayer
对象上,也就是说该对象负责进行裁剪。
总的来说 PhysicalShape
还是非常简单的,就是一个加强版的 ClipPath
,具有阴影效果。下面分别是 PhysicalShape
(左) 和 ClipPath
(右)的裁剪效果。可以看出PhysicalShape
并没有小剪刀,说明它不是通过画布的路径裁剪实现的。
如果跟踪裁剪器的路径流向,我们可以发现最终 path
被用于 SceneBuilder#_pushPhysicalShape
的 native
方法中。所以说 PhysicalShape
和 ClipPath
在本质上的实现还是有差异的。
那PhysicalShape
的使用方式到这里就介绍完毕,那本文到这里就结束了,谢谢观看,明天见~