前言:
這是我參與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
的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~