(兩百六十三)Flutter - 學習處理邊界約束 (Box constraints) 的問題

https://flutter.cn/docs/development/ui/layout/box-constraints

處理邊界約束 (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 嵌套在水平滾動的 ListView 內,那麼被嵌套在裏面的垂直滾動的 ListView 將會試圖儘可能寬,直到無限寬,因爲將其嵌套的是一個水平滾動的ListView,它可以在水平方向上一直滾動。

 

Flex

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

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

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

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

 

之前用到flex是設定各個Row或者Column的各個widget的weight

https://blog.csdn.net/sinat_20059415/article/details/105800739

也許你想要一個 widget 佔用的空間是兄弟項的兩倍。爲了達到這個效果,可以使用 Expanded widget 的 flex 屬性,這是一個用來確定 widget 的彈性係數的整數。默認的彈性係數爲 1。以下代碼將中間圖像的彈性係數設置爲 2:

content_copy

    Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Expanded(
          child: Image.asset('images/pic1.jpg'),
        ),
        Expanded(
          flex: 2,
          child: Image.asset('images/pic2.jpg'),
        ),
        Expanded(
          child: Image.asset('images/pic3.jpg'),
        ),
      ],
    );

 

Understanding constraints

https://flutter.cn/docs/development/ui/layout/constraints

When someone learning Flutter asks you why some widget with width:100 isn’t 100 pixels wide, the default answer is to tell them to put that widget inside of a Center, right?

Don’t do that.

If you do, they’ll come back again and again, asking why some FittedBox isn’t working, why that Column is overflowing, or what IntrinsicWidth is supposed to be doing.

Instead, first tell them that Flutter layout is very different from HTML layout (which is probably where they’re coming from), and then make them memorize the following rule:

Constraints go down. Sizes go up. Parent sets position.

Flutter layout can’t really be understood without knowing this rule, so Flutter developers should learn it early on.

In more detail:

  • A widget gets its own constraints from its parent. A constraint is just a set of 4 doubles: a minimum and maximum width, and a minimum and maximum height.
  • Then the widget goes through its own list of children. One by one, the widget tells its children what their constraints are (which can be different for each child), and then asks each child what size it wants to be.
  • Then, the widget positions its children (horizontally in the x axis, and vertically in the y axis), one by one.
  • And, finally, the widget tells its parent about its own size (within the original constraints, of course).

For example, if a composed widget contains a column with some padding, and wants to lay out its two children as follows:

 

The negotiation goes something like this:

Widget: “Hey parent, what are my constraints?”

Parent: “You must be from 80 to 300 pixels wide, and 30 to 85 tall.”

Widget: “Hmmm, since I want to have 5 pixels of padding, then my children can have at most 290 pixels of width and 75 pixels of height.”

Widget: “Hey first child, You must be from 0 to 290 pixels wide, and 0 to 75 tall.”

First child: “OK, then I wish to be 290 pixels wide, and 20 pixels tall.”

Widget: “Hmmm, since I want to put my second child below the first one, this leaves only 55 pixels of height for my second child.”

Widget: “Hey second child, You must be from 0 to 290 wide, and 0 to 55 tall.”

Second child: “OK, I wish to be 140 pixels wide, and 30 pixels tall.”

Widget: “Very well. My first child has position x: 5 and y: 5, and my second child has x: 80 and y: 25.”

Widget: “Hey parent, I’ve decided that my size is going to be 300 pixels wide, and 60 pixels tall.”

Limitations

As a result of the layout rule mentioned above, Flutter’s layout engine has a few important limitations:

  • A widget can decide its own size only within the constraints given to it by its parent. This means a widget usually can’t have any size it wants.

  • A widget can’t know and doesn’t decide its own position in the screen, since it’s the widget’s parent who decides the position of the widget.

  • Since the parent’s size and position, in its turn, also depends on its own parent, it’s impossible to precisely define the size and position of any widget without taking into consideration the tree as a whole.

 

總結

簡單來說各個widget都有對應的寬和高的限制,若無限制,則不能進行簡單的分塊操作,比如expanded,這種情況下子widget會自適應佈局,從代碼角度而言就是分塊操作無法得知具體widget的高寬,以至於無法準確繪製。

另外學習下flutter佈局的流程

  • A widget gets its own constraints from its parent. A constraint is just a set of 4 doubles: a minimum and maximum width, and a minimum and maximum height.
  • Then the widget goes through its own list of children. One by one, the widget tells its children what their constraints are (which can be different for each child), and then asks each child what size it wants to be.
  • Then, the widget positions its children (horizontally in the x axis, and vertically in the y axis), one by one.
  • And, finally, the widget tells its parent about its own size (within the original constraints, of course).

和要領

Constraints go down. Sizes go up. Parent sets position.

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章