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

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

這是我參與8月更文挑戰的第 18 天,活動詳情檢視: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 [本文]

一、認識 Divider 元件

Divider 元件大家都很熟悉,就是一根水平的分割線,可以指定高度、粗細、顏色、邊距。那這些屬性預設是什麼,如何統一設定預設值,Divider 元件的原始碼又是如何實現的呢?本文就來詳細介紹一下。


1. Divider 基本資訊

下面是 Divider 元件類的定義構造方法,可以看出它繼承自 StatelessWidget。有五個可選引數:

image-20210818081625700


2.Divider 的尺寸分析

先看一下 Divider 的尺寸特點:下面先通過[w(10,200) - h(0,200)] 的約束。Divider 可以通過 height 指定其尺寸區域高度,而寬度是父級約束的最大值。 注: [w(a,b) - h(c,d)] 表示,尺寸約束寬在 a 和 b 之間,高在 c 和 d 之間。

class DividerDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ConstrainedBox(
      constraints: BoxConstraints(
        maxWidth: 200,
        minWidth: 10,
        maxHeight: 200,
        minHeight: 0
      ),
      child: Divider(
        height: 10,
      ),
    );
  }
}
複製程式碼

當約束改為[w(10,200) - h(50,200)] ,可以看出 Divider 指定的高就會無效。也就是說 Divider 指定的高並非一定生效,它會受到父級區域約束的管控。

class DividerDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ConstrainedBox(
      constraints: BoxConstraints(
        maxWidth: 200,
        minWidth: 10,
        maxHeight: 200,
        minHeight: 50
      ),
      child: Divider(
        height: 10,
      ),
    );
  }
}
複製程式碼

如果通過 UnconstrainedBox 接觸父級的約束,那麼 Divider 元件由於寬度沒有限制,就不會顯示。這也說明了父級的區域約束對 Divider 元件是很重要的。

通過渲染樹可以看出,Divider 元件對應的渲染物件最終尺寸為 Size(0,0) ,這也就解釋了為什麼在無約束的情況下,Divider 元件不會顯示。

class DividerDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ConstrainedBox(
      constraints: BoxConstraints(
        maxWidth: 200,
        minWidth: 10,
        maxHeight: 200,
        minHeight: 50
      ),
      child: UnconstrainedBox(
        child: Divider(
            height: 10,
        ),
      ),
    );
  }
}
複製程式碼

3.Divider 的屬性

這些屬性的含義都很簡單,下面程式碼是三條分割線。

屬性名型別預設值用途
heightdoublenull元件高
thicknessdoublenull線粗細
indentdoublenull左邊距
endIndentdoublenull右邊距
colorColornull線顏色

class DividerDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return  Container(
      width: 200,
      child: Wrap(
          children:[
            const Divider(
              height: 10,
              indent: 20,
              endIndent: 20,
              thickness: 1,
              color: Colors.orange,
            ),
            const Divider(
              height: 10,
              indent: 10,
              endIndent: 10,
              thickness: 2,
              color: Colors.blueAccent,
            ),
            const Divider(
              height: 10,
            ),
          ],
      ),
    );
  }
}
複製程式碼

其中 indentendIndent 可以用於類似這樣的邊距,就不需要額外套 Padding 實現了。


4.Divider 的預設屬性

如果一個應用中需要指定預設的 Divider 樣式,每次使用都設定一下顯然很麻煩。Flutter 中有相關的主題元件 DividerTheme ,其中維護了 DividerThemeData 資料。我們可以通過 該元件使其子節點的 Divider 按照預設樣式進行展現。效果如下:

class DividerDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return  DividerTheme(
      data: DividerThemeData(
        color: Colors.orange,
        thickness: 1/window.devicePixelRatio,
        space: 5
      ),
      child: Container(
        width: 200,
        child: Wrap(
            children:[
              const Divider(),
              const Divider(),
              const Divider(),
            ],
        ),
      ),
    );
  }
}
複製程式碼

二、 Divider 的原始碼實現

首先,它是 StatelessWidget,只能依賴於其他元件進行構建,核心邏輯在 build 方法中。

另外注意一下,在構造方法的斷言中,四個數字屬性都不能為負數


build 方法也比較簡單,首先通過 DividerTheme 獲取資料,可以看出如果沒有設定主體,預設的高度是 16 邏輯畫素。也就是說這時 Divider 本身是有一定的高度佔位的。區域尺寸通過 SizedBox 設定,分割線是通過 Container 裝飾的底邊線完成的。其中 indentendIndent 作用於 margin 屬性,本質還是通過 Padding 元件完成的邊距。

通過除錯可以看出預設 DividerTheme 中的資料屬性為 null ,那問題來了 Divider 的預設顏色是什麼?

createBorderSide 靜態方法中,可以看出,如果 DividerTheme 顏色為 null ,會根據 Theme 中的 dividerColor 設定顏色。

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

相關文章