前言:
這是我參與8月更文挑戰的第 21 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰
,我準備在本月挑選 31
個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄
的重要素材。希望可以堅持下去,你的支援將是我最大的動力~
一、認識 SizedBox 元件
原始碼中對 SizedBox
的介紹為:一個指定尺寸的盒子。那 SizedBox
為什麼可以限定尺寸?背後區域限定的原理又是什麼? 本文通過 SizedBox
來一窺佈局約束奧祕的冰山一角。
1.SizedBox 基本資訊
下面是 SizedBox
元件類的定義
和 構造方法
,可以看出它繼承自 SingleChildRenderObjectWidget
。可接受一個子元件,和區域的寬高。
2.SizedBox 的使用
如下,是一個 100*50
的 SizedBox
,通過 ColoredBox
塗上藍色,效果如下:
SizedBox(
width: 100,
height: 50,
child: ColoredBox(
color: Colors.blue.withAlpha(88)
),
),
複製程式碼
3.區域分析
乍一看,不就是一個元件提供寬高來設定尺寸嗎,似乎並沒有什麼好延伸的。但你有沒有想過,為什麼 SizedBox
有權力決定尺寸大小?它決定的區域一定有效嗎?在分析之前,先了解一些前置知識:
任何元件的佔位區域
、繪製內容
最終都取決於 RenderObject
。而並非所有的元件都和 RenderObject
有關,只有 RenderObjectWidget
負責維護 RenderObject
。像 StatelessWidget
和 StatefulWidget
這種都是基於已有元件進行組合,往深層去看,他們都是基於某些 RenderObjectWidget
實現。
關於佈局, RenderObject
有一個非常重要的屬性: Constraints
型別的 constraints
,表示自身受到的區域約束限制。而 RenderBox
作為 RenderObject
的子類,擴充出了 size
的概念,絕大多陣列件維護的渲染物件
都是在 RenderBox
基礎上進行擴充的。
下面來開啟元件樹,一起來看一下:
上面的 SizedBox
元件,它維護的 RenderObject
是 RenderConstrainedBox
,自身的約束為 [w(0,800) - h(0,600)]
,也就說明該渲染物件的大小必須在這此區間內。然後它會給子元件施加一個額外的約束 [w(100,100) - h(50,50)]
。
這樣對於 ColoredBox
對應的渲染物件 _RenderColoredBox
,由於父級施加的額外約束,自身的約束也就變成 [w(100,100) - h(50,50)]
。也就說明該渲染物件的大小必須在這此區間內,即 _RenderColoredBox
的尺寸被限定為 (100,50)
。
_RenderColoredBox
的 size
確定後,RenderConstrainedBox
會根據自身的約束和子節點的尺寸來確定自身的尺寸。這就是 SizedBox
的工作原理。
4、約束測試
為了更好地說明約束的作用,這裡進行一下測試,在之前的案例的 SizedBox
外層通過 ConstrainedBox
元件新增新增一個 [w(20,20) - h(20,20)]
的強制約束。可以看出即使 SizedBox
設定了固定的寬高,但是在外層的約束之下,會優先滿足父級約束。
[推論1] SizedBox 的最終尺寸會受到父級約束的影響,並非一定為指定值。
複製程式碼
ConstrainedBox(
constraints: BoxConstraints(
minWidth: 20,
maxWidth: 20,
maxHeight: 20,
minHeight: 20,
),
child: SizedBox(
width: 100,
height: 50,
child: ColoredBox(color: Colors.blue.withAlpha(88)),
),
);
複製程式碼
我們再來看一下此時的元件樹:
可以看出 SizedBox
維護的 RenderConstrainedBox
本身的約束區域為 [w(20,20) - h(20,20)]
,為子節點施加的額外約束為 [w(100,100) - h(50,50)]
。在 ColoredBox
維護的 _RenderColoredBox
中,約束區域為 [w(20,20) - h(20,20)]
,這也就覺得了其尺寸為 (20,20)
。
這樣可以看出,渲染物件對子節點施加的額外約束
,並不會完全作用於子節點。還會根據自身的約束情況,來確定子元件的最終約束。
三、SizedBox 的原始碼分析
SizedBox
繼承自 SingleChildRenderObjectWidget
,就說明它需要維護一個 RenderObject
來實現功能。
在前面我們通過元件樹可以看出,它維護的渲染物件是 RenderConstrainedBox
。從原始碼中可以看出, RenderConstrainedBox
構造時需要傳入一個約束物件 BoxConstraints
。這裡通過 BoxConstraints.tightFor
構造使用 width
和 height
建立一個緊約束。
通過原始碼可以看出,這個構造的約束為: [w(width,width) - h(height,height)]
,也就是固定寬高約束。
SizedBox
除了普通構造之外,還有三個命名構造。如果已經瞭解上面的用法,那這三個也非常簡單,都逃離不了對寬高的初始化。比如 .expand
會建立一個無限的約束,這樣由於 推論1
,其約束的尺寸就可以在父級的約束
下,儘可能的大 。 .shrink
就是一個 [w(0,0) - h(0,0)]
的限制,同理,會在父級的約束
下,儘可能的小。
至於 RenderConstrainedBox
渲染物件的實現,將在後面的 ConstrainedBox
一文中進行介紹,畢竟 RenderConstrainedBox
的本命是 ConstrainedBox
。通過本文,你應該對 SizedBox
有了更深的認識,對佈局約束、尺寸確定也認識了九牛一毛 。那本文到這裡就結束了,謝謝觀看,明天見~