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

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

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

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

一、認識 Padding 元件

說到 Padding ,應該是大家入門 Flutter 時學習的第一批元件。它的功能非常簡單,就是為子元件新增邊距。本文就回到 夢的起點 ,來好好說說 Padding元件的使用與其原始碼實現。


1.Padding 基本資訊

下面是 Padding 元件類的定義構造方法,可以看出它繼承自 SingleChildRenderObjectWidget。例項化時必須傳入 padding 引數,其中padding 的型別為 EdgeInsetsGeometry 。另外,還能傳入一個 child 元件。

final EdgeInsetsGeometry padding;
複製程式碼

2. Padding 元件的使用

比如下面的灰色盒子中有一個 Icon 元件。這時想讓它四周有 10 的邊距,我們就可以通過 Padding 元件完成。

如下 tag1 處,通過 Padding 元件,指定 padding 值,效果如下:

class PaddingDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      width: 100,
      alignment: Alignment.topLeft,
      color: Colors.black12,
      child: const Padding( //<--- tag1
        padding: EdgeInsets.all(10),
        child: Icon(
          Icons.ac_unit,
          size: 40,
          color: Colors.green,
        ),
      ),
    );
  }
}
複製程式碼

無論是可見的還是不可見的元件,都有其尺寸區域。那加上 EdgeInsets.all(10) 邊距之後,Padding 元件的尺寸區域是什麼?下面有三個選項:


通過佈局檢視器可以知道,選 A 。我們都知道 padding 是內邊距,margin 是外邊距。從 Icon 元件的角度來看,似乎是為其新增了 外邊距 來實現功能。但使用 Padding 元件,應該站在 Padding 元件的角度來看待問題:這樣對於 child 元件就是通過 內邊距 ,擴充了 Padding 元件的佔位區域。


由於 Padding 元件的邊距區域是不可見的,但佔據空間,當其他元件並列排布,感覺上是兩者之間有一個留白

其中被包裹的 Icon 元件本身並沒有任何變化, Padding 元件可以在任意的元件外巢狀,這種 可插拔 的功能實現模式,是 Flutter 的一大特點,這樣可以極大程度地降低元件間的耦合性,使用起來更加靈活。Padding 元件的功能非常簡單,但其中的思想是非常值得學習的:

幾乎任何元件都可能使用到 padding 屬性操作邊距,然而框架並沒有將 padding 屬性作為 Widget 的公共屬性。這些通用的屬性無法預測有多少,如果都作為 Widget 的公共屬性,維護起來自然麻煩, Widget 本身也就自然繁重。而分離出不同的元件實現功能,通過元件組合的進行使用,這樣可以各取所需,自然高明許多。


3. 認識 EdgeInsetsGeometry

其實邊距本身就是 左上右下 四個數字。Flutter 裡將這四個數字抽象為 EdgeInsetsGeometry 。可以看出它是 const 構造,也就是說 EdgeInsetsGeometry 物件一旦建立,就無法修改該物件的屬性值。這也是為什麼六個屬性通過 get 方法獲取,卻沒有 set 方法設定的原因。


EdgeInsetsGeometry 作為抽象類自然是無法直接使用的,其可用的實現類有 EdgeInsetsEdgeInsetsDirectional

我們最常使用的是 EdgeInsets ,通過 左上右下 來控制邊距大小。其中維護了四個屬性值,通過構造進行初始化。

主要構造有如下四個:

EdgeInsets.fromLTRB  // 指定左、上、右、下、四個邊距值(必須傳入四參)
EdgeInsets.all       // 指定一個值,用於左、上、右、下邊距
EdgeInsets.only      // 指定左、上、右、下、四個邊距值(入參任意)
EdgeInsets.symmetric // 指定水平/豎直邊距值
複製程式碼

另外,由於其中過載了一下運算子,也就說明,兩個 EdgeInsets 物件間可以進行運算子計算。


另外一個子類 EdgeInsetsDirectional 用的比較少,其功能基本一致,只不過是 開始、上、結束、下 的邊界語義。一般來說,我們更習慣於 左上右下 的語義,而且 EdgeInsets 字母比較少。


二、 Padding 元件的原始碼實現

1. Padding 原始碼分析

它繼承自 SingleChildRenderObjectWidget 就說明,該元件需要維護一個 RenderObject 物件的建立及更新。

createRenderObject 方法中,建立 RenderPaddingpadding 作為構造入參。在 updateRenderObject 中,對 RenderPadding 物件進行更新。也就是說,新增邊距的功能是在 RenderPadding 中實現的。


2. RenderPadding 原始碼

RenderPadding 中最主要的操作是在 performLayout 方法中進步佈局處理。可以看出,如果 child 為空,會將 RenderPadding 的尺寸根據 _resolvedPadding 進行處理。也就是說,即使沒有子元件,Padding 也可以有佔位區間。

如果子元件非空,那麼 RenderPadding 的尺寸會根據 _resolvedPadding 和 子元件的尺寸進行計算得出。其實我們一直說 元件的佔位區域其實並不嚴謹,Widget 本身只是屬性配置類而已,真正有尺寸 size 概念的是 RenderObject 。只不過 RenderObject 都有對應的 RenderObjectWidget 進行維護,我們說元件的尺寸,更加形象,容易理解。

最後,在 child 繪製時,可以看出做了偏移處理。這也是為什麼加了 Padding 元件後,子元件繪製的位置會變化的原因。

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

相關文章