處理邊界約束 (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 (RowColumn)內以及 可滾動區域(ListView 和其它 ScrollView 的子類別)內時。

特別是 ListView 會試圖擴充以適應其交叉方向可用空間 (比如說,如果它是一個垂直滾動塊,它將試圖擴充到與其父 widget 一樣寬)。如果讓垂直滾動的 ListView 巢狀(Nesting)在水平滾動的 ListView 內,那麼被巢狀(Nesting)在裡面的垂直滾動的 ListView 將會試圖儘可能寬,直到無限寬,因為將其巢狀(Nesting)的是一個水平滾動的ListView,它可以在水平方向上一直滾動。

Flex

Flex 框本身(RowColumn)的行為會有所不同,這取決於其在給定方向上是處於有邊界約束還是無邊界約束。

在有邊界約束條件下,它們在給定方向上會盡可能大。

在無邊界約束條件下,它們試圖讓其子 widget 自適應這個給定的方向。在這種情況下,不能將子 widget 的flex屬性設定為 0(預設值)以外的任何值。這意味著在 widget 庫中,當一個 flex 框巢狀(Nesting)在另外一個 flex 框或者巢狀(Nesting)在可滾動區域內時,不能使用 Expanded。如果這樣做了,就會收到例外,該例外資訊會把你引導到本頁面。

交叉 方向上,如 Column(垂直的 flex)的寬度和 Row(水平的 flex)的高度,它們必將不能是無界的,否則它們將無法合理地對齊它們的子 widget。