【Flutter 元件集錄】PhysicalShape | 8 月更文挑戰

張風捷特烈發表於2021-08-17
前言:

這是我參與8月更文挑戰的第 17 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰,我準備在本月挑選 31 個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄 的重要素材。希望可以堅持下去,你的支援將是我最大的動力~

本系列元件文章列表
1.NotificationListener2.Dismissible3.Switch
4.Scrollbar5.ClipPath6.CupertinoActivityIndicator
7.Opacity8.FadeTransition9. AnimatedOpacity
10. FadeInImage11. Offstage12. TickerMode
13. Visibility14. Padding15. AnimatedContainer
16.CircleAvatar17.PhysicalShape[本文]

一、認識 PhysicalShape 元件

大家應該沒怎麼用過 PhysicalShape ,從名字中可以看出它是 Physical + Shape ,也就是物理性狀。從註釋中可以看出,它的作用是將子元件根據路徑裁剪,這時你應該會想到 ClipPath 元件。另外可以看出這個裁剪可以具有陰影效果。


1. PhysicalShape 基本資訊

下面是 PhysicalShape 元件類的定義構造方法,可以看出它繼承自 SingleChildRenderObjectWidget。例項化時必須傳入 clippercolor 引數。

其中 clipper 引數的型別為 CustomClipper<Path> ,這和 ClipPath 中的 clipper 入參一樣。

final CustomClipper<Path> clipper;
複製程式碼

另外,可以指定影深 elevation、陰影看色 shadowColor 、和裁剪行為 clipBehavior。可見預設情況想是沒有影深的,陰影顏色為黑色。


2. PhysicalShape 的使用

對於 CustomClipper<Path> 物件,在 ClipPath 元件 一文中已經詳細介紹了,這裡不再贅述,可詳見之。先看兩個必須的入參 clippercolor 。如下,通過 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 可以通過 elevationshadowColor 來指定陰影,效果如下:

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 原始碼簡看

它繼承自 SingleChildRenderObjectWidget,會維護 RenderObject 物件。可以看出它通過 RenderPhysicalShape 渲染物件實現功能。其中顏色、裁剪器、陰影等屬性都是構建 RenderPhysicalShape 的入參。


RenderPhysicalShape#paint 中,開始會進行陰影的繪製。

裁剪器被設定到 PhysicalModelLayer 物件上,也就是說該物件負責進行裁剪。

總的來說 PhysicalShape 還是非常簡單的,就是一個加強版的 ClipPath ,具有陰影效果。下面分別是 PhysicalShape (左) 和 ClipPath (右)的裁剪效果。可以看出PhysicalShape 並沒有小剪刀,說明它不是通過畫布的路徑裁剪實現的。

如果跟蹤裁剪器的路徑流向,我們可以發現最終 path 被用於 SceneBuilder#_pushPhysicalShapenative 方法中。所以說 PhysicalShapeClipPath 在本質上的實現還是有差異的。

PhysicalShape 的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~

相關文章