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

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

這是我參與8月更文挑戰的第 28 天,活動詳情檢視: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.PhysicalShape18.Divider
19.Flexible、Expanded 和 Spacer 20.Card21.SizedBox
22.ConstrainedBox23.Stack24.Positioned
25.OverflowBox26.SizedOverflowBox27. DecoratedBox
28. BackdropFilter

1.認識 BackdropFilter 元件

BackdropFilter 元件可能很少人使用,但它的功能還是很強大的。原始碼中對它的介紹是:對已有的繪製內容新增一個過濾器,然後再繪製它的孩子。


下面是 BackdropFilter 元件類的定義構造方法,可以看出它繼承自 SingleChildRenderObjectWidget 。構造時必須傳入尺寸 filter 引數,其型別是 ImageFilter

final ui.ImageFilter filter;
複製程式碼

2.BackdropFilter 的使用

原始碼中有一個 BackdropFilter 元件的測試案例,我們先基於這個案例,看一下 BackdropFilter 的效果及作用。下圖中,有三個區域: 01文字紫色區域Hello World 文字。實現的方式是:通過 Stack 疊合 01文字BackdropFilter ,其中紫色區域和Hello World 文字是 BackdropFilter 的子元件。

class CustomBackdropFilter extends StatelessWidget {
  final Random random = Random();

  @override
  Widget build(BuildContext context) {
    String data = '';
    for (int i = 0; i < 10000; i++) {
      data += random.nextBool() ? " 0 " : " 1 ";
    }

    return Stack(
      children: <Widget>[
        Text(data),
        Center(child: buildFilterZone(),),
      ],
    );
  }

  Widget buildFilterZone() {
    return BackdropFilter(
      filter: ui.ImageFilter.blur(
        sigmaX: 2.0,
        sigmaY: 2.0,
      ),
      child: Container(
        alignment: Alignment.center,
        width: 200.0,
        height: 120.0,
        color: Colors.purple.withOpacity(0.1),
        child: const Text(
          'Hello World',
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }
}
複製程式碼

從佈局檢視器中可以看出:BackdropFilter 的區域只是紫色部分,模糊遮罩並不會對其子元件產生影響。就像是在元件上層覆蓋一個模糊層,而是子元件會在模糊層之上。


有時我們可能只是對某個區域進行遮罩處理,可以通過 ClipRRect 等裁剪元件進行裁剪,這樣模糊層 就不會影響之外的部分。如下是圓角矩形的裁剪效果:

ClipRRect(
  borderRadius: BorderRadius.circular(20),
  child: buildFilterZone(),
),
複製程式碼

3. 認識 ImageFilter

首先 ImageFilter 是一個抽象類,但它可以通過命名構造建立物件,如下有三種構造方式。

ImageFilter.blur 來說,可以看到構造前面有一個 factory 關鍵字,以此讓抽象類也可以建立物件。可以看出這個構造本質上是使用了 _GaussianBlurImageFilter ,也就是高斯模糊。兩個入參 sigmaXsigmaY 是模糊的程度。


比如下面是 x:2.0,y:2.0 的效果:

這是 x:4.0,y:1.0 的效果:

這是 x:6.0,y:6.0 的效果:

可見 sigmaXsigmaY 分別控制 XY 方向上的模糊程度。


除了通過 ImageFilter.blur 建立 模糊遮罩,還可以通過 ImageFilter.matrix 對區域內進行矩陣變換,如下面的 skewX

Widget buildFilterZone() {
  return BackdropFilter(
    filter:
    ui.ImageFilter.matrix(Matrix4.skewX(45/180*pi).storage),
    child: Container(
      alignment: Alignment.center,
      width: 200.0,
      height: 120.0,
      color: Colors.blueAccent.withOpacity(0.1),
      child: const Text(
        'Hello World',
        style: TextStyle(fontSize: 24),
      ),
    ),
  );
}
複製程式碼

4. BackdropFilter 元件的原始碼實現

BackdropFilter 繼承自 SingleChildRenderObjectWidget ,內部維護 RenderBackdropFilter 渲染物件來實現新增濾色器功能。

image-20210828154123795


RenderBackdropFilter#paint 中建立 BackdropFilterLayer 物件 layer,並將傳入的 filter 設定給 layer 。通過 context.pushLayer 新增一個層,實現濾色器功能。

那本文到這裡就結束了,謝謝觀看,明天見~

相關文章