前言:
這是我參與8月更文挑戰的第 14 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰
,我準備在本月挑選 31
個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄
的重要素材。希望可以堅持下去,你的支援將是我最大的動力~
一、認識 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
作為抽象類自然是無法直接使用的,其可用的實現類有 EdgeInsets
和 EdgeInsetsDirectional
。
我們最常使用的是 EdgeInsets
,通過 左上右下
來控制邊距大小。其中維護了四個屬性值,通過構造進行初始化。
主要構造有如下四個:
EdgeInsets.fromLTRB // 指定左、上、右、下、四個邊距值(必須傳入四參)
EdgeInsets.all // 指定一個值,用於左、上、右、下邊距
EdgeInsets.only // 指定左、上、右、下、四個邊距值(入參任意)
EdgeInsets.symmetric // 指定水平/豎直邊距值
複製程式碼
另外,由於其中過載了一下運算子,也就說明,兩個 EdgeInsets
物件間可以進行運算子計算。
另外一個子類 EdgeInsetsDirectional
用的比較少,其功能基本一致,只不過是 開始、上、結束、下
的邊界語義。一般來說,我們更習慣於 左上右下
的語義,而且 EdgeInsets
字母比較少。
二、 Padding 元件的原始碼實現
1. Padding 原始碼分析
它繼承自 SingleChildRenderObjectWidget
就說明,該元件需要維護一個 RenderObject
物件的建立及更新。
在 createRenderObject
方法中,建立 RenderPadding
,padding
作為構造入參。在 updateRenderObject
中,對 RenderPadding
物件進行更新。也就是說,新增邊距的功能是在 RenderPadding
中實現的。
2. RenderPadding 原始碼
RenderPadding
中最主要的操作是在 performLayout
方法中進步佈局處理。可以看出,如果 child
為空,會將 RenderPadding
的尺寸根據 _resolvedPadding
進行處理。也就是說,即使沒有子元件,Padding
也可以有佔位區間。
如果子元件非空,那麼 RenderPadding
的尺寸會根據 _resolvedPadding
和 子元件的尺寸進行計算得出。其實我們一直說 元件的佔位區域
其實並不嚴謹,Widget
本身只是屬性配置類而已,真正有尺寸 size
概念的是 RenderObject
。只不過 RenderObject
都有對應的 RenderObjectWidget
進行維護,我們說元件的尺寸,更加形象,容易理解。
最後,在 child
繪製時,可以看出做了偏移處理。這也是為什麼加了 Padding
元件後,子元件繪製的位置會變化的原因。
那Padding
的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~