處理邊界約束 (Box constraints) 的問題
Flutter 中的 widget 由在其底層的 RenderBox
物件渲染而成。渲染框由其父級 widget 給出約束,並根據這些約束調整自身尺寸大小。約束是由最小寬度、最大寬度、最小高度、最大高度四個方面構成;尺寸大小則由特定的寬度和高度兩個方面構成。
一般來說,從如何處理約束的角度來看,有以下三種類型的渲染框:
對於一些諸如 Container
的 widget,其尺寸會因構造方法的引數而異,就 Container
來說,它預設是儘可能大的,而一旦給它一個特定的寬度,那麼它就會遵照這個特定的寬度來調整自身尺寸。
其它一些像 Row
and Column
(flex boxes)這樣的 widget ,其尺寸會因給定的約束而異,具體細節見後文 “Flex” 部分;
約束有時是”緊密的”,這意味著這些約束嚴格地限定了渲染框在定奪自身尺寸方面的空間(例如:當約束的最小寬度和最大寬度相同時,這種情況下,我們稱這個約束有緊密寬度),這方面的主要例子是 App Widget,它是 RenderView
類裡面的一個 widget:
由應用程式的 build
函式返回的子 widget 渲染框被指定了一個約束,該約束強制 App Widget 精確填充應用程式的內容區域(通常是整個螢幕)。
Flutter 中的許多渲染框,特別是那些只包含單個 widget 的渲染框,都會將自身的約束傳遞給他們的子級 widget。這意味著如果你在應用程式渲染樹的根部嵌套了一些渲染框,這些框將會在受到約束的影響下相互適應彼此。
有些渲染框放鬆了約束,即:約束中只有最大寬度,最大高度,但沒有最小寬度,最小高度,例如 Center
。
無邊界約束
在某些情況下,傳遞給框的約束是 無邊界 的或無限的。這意味著約束的最大寬度或最大高度為 double.infinity
。
當傳遞無邊界約束給型別為儘可能大的框時會失效,在 debug 模式下,則會丟擲例外,該例外資訊會把你引導到本頁面。
渲染框具有無邊界約束的最常見情況是:當其被置於 flex boxes (Row
和 Column
)內以及
可滾動區域(ListView
和其它 ScrollView
的子類別)內時。
特別是 ListView
會試圖擴充以適應其交叉方向可用空間
(比如說,如果它是一個垂直滾動塊,它將試圖擴充到與其父 widget 一樣寬)。如果讓垂直滾動的 ListView
巢狀(Nesting)在水平滾動的 ListView
內,那麼被巢狀(Nesting)在裡面的垂直滾動的 ListView
將會試圖儘可能寬,直到無限寬,因為將其巢狀(Nesting)的是一個水平滾動的ListView
,它可以在水平方向上一直滾動。
Flex
Flex 框本身(Row
和 Column
)的行為會有所不同,這取決於其在給定方向上是處於有邊界約束還是無邊界約束。
在有邊界約束條件下,它們在給定方向上會盡可能大。
在無邊界約束條件下,它們試圖讓其子 widget 自適應這個給定的方向。在這種情況下,不能將子 widget 的flex
屬性設定為 0(預設值)以外的任何值。這意味著在 widget 庫中,當一個 flex 框巢狀(Nesting)在另外一個 flex 框或者巢狀(Nesting)在可滾動區域內時,不能使用 Expanded
。如果這樣做了,就會收到例外,該例外資訊會把你引導到本頁面。
在 交叉 方向上,如 Column
(垂直的 flex)的寬度和
Row
(水平的 flex)的高度,它們必將不能是無界的,否則它們將無法合理地對齊它們的子 widget。