我們在flutter中使用layout的時候需要經常對元件進行一些大小的限制,這種限制就叫做constraints,用來控制layout中的元件大小。
掌握了constraints才算對layout有了真正的瞭解,但是flutter中的constraints和我們熟悉的HTML中的constraints區別比較大,所以我們還是需要深入瞭解flutter中contraints的特性。
對於constraints來說,只有四個屬性,分別是最小width,最大width,最小height和最大height。這四個屬性所能限制的就是寬度和高度的範圍。
根據這兩個屬性的範圍不同,constraints可以分為tight constraints和loose constraints。
那麼tight和loose有什麼區別呢?
對於tight來說,它的 maximum width = minimum width, 並且maximum height = minimum height, 也就是說為width和height提供了一個特定的值。
具體而言,可以看下BoxConstraints的tight實現:
BoxConstraints.tight(Size size)
: minWidth = size.width,
maxWidth = size.width,
minHeight = size.height,
maxHeight = size.height;
和tight相對應的就是loose,在loose中我們設定了最大的width和height,但是希望widget越小越好,這樣對應width和height的最小值為0,同樣以BoxConstraints為例看下它的定義:
BoxConstraints.loose(Size size)
: minWidth = 0.0,
maxWidth = size.width,
minHeight = 0.0,
maxHeight = size.height;
前面我們講到了constraints的分類,這裡我們會講一下constraints的基本原則。
通常來說,在flutter中,一個widget的constraints是從它的parent繼承而來的。然後這個widget會將constraints告訴他的子widget.
子widget會有自己定義的大小,那麼子widget會根據自己定義的大小來設定自己的大小,並將結果反饋跟父widget,父widget會最終根據所有子widget的大小來設定自己的大小。
所以總結而言就是,constraints是向下傳遞的,而size是向上傳遞的。
可能大家還不太明白是什麼意思,沒關係,接下來我們用具體的例子來說明。
首先,我們使用BoxConstraints.tightFor來建立一個儘可能大的width和height的Constraints,然後在這個constraint內部新建widget來觀察他們的表現。
ConstrainedBox(
constraints: const BoxConstraints.tightFor(
width: double.infinity, height: double.infinity),
child: exampleWidget)
通過替換上面的exampleWidget,我們來觀察不同的表現形式。
首先是最基礎的Container,對於Container本身來說,他可以設定width和height,但是這兩個屬性並不是constraint,所以還得從parent widget中繼承。
那麼對於下面的一個widget來說:
Widget build(BuildContext context) {
return Container(color: blue);
}
它會使用從parent繼承的constraints,也就是說盡可能的大,所以會展示下面的介面:
填滿所有的區域。
如果給Container指定了width和hight,同樣的,Container需要從parent繼承constraints,所以仍然是填滿整個區域:
Widget build(BuildContext context) {
return Container(width: 100, height: 100, color: blue);
}
但是,如果我們在Container的外面再加上一個constraints,比如Center:
Widget build(BuildContext context) {
return Center(
child: Container(width: 100, height: 100, color: blue),
);
}
那麼雖然Center會從parent繼承constraints,去填滿整個區域,但是Center本身的constraints是告訴子widget可以按照他自己的意願來調整大小,所以這個時候最終Container的大小就是100x100:
除了Center之外,我們還可以使用Align,效果和Center是一致的:
Widget build(BuildContext context) {
return Align(
alignment: Alignment.bottomLeft,
child: Container(width: 100, height: 100, color: blue),
);
}
下面是一個使用Center的很有趣的例子:
Widget build(BuildContext context) {
return Center(
child: Container(
color: blue,
child: Container(color: green, width: 30, height: 30),
),
);
}
這裡Center中有一個Container,Container中有一個Container,但是這兩個Container設定了不同的顏色。
因為外層的Container並沒有設定大小,所以他的大小是由child Container來決定的,因為兩個Container大小一樣,所以外部的顏色會被內部的覆蓋,我們可以得到下面的介面:
如果我們給外層的新增一個padding如下:
Widget build(BuildContext context) {
return Center(
child: Container(
padding: const EdgeInsets.all(20.0),
color: blue,
child: Container(color: green, width: 30, height: 30),
),
);
}
那麼外層現在就比內層的widget要大了,顏色也可以展示出來了:
我們再來看下面的例子:
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 70,
minHeight: 70,
maxWidth: 150,
maxHeight: 150,
),
child: Container(color: blue, width: 10, height: 10),
);
}
上面的例子在Container外面新增了一個ConstrainedBox,指定了四個constraints屬性,但是這個ConstrainedBox並不會應用到child上,所以最終得到的介面還是全部的藍色。
為什麼呢?這是因為不同的widget對constraints有不同的定義,對於ConstrainedBox來說,他是一個對其子項施加額外約束的小部件。記住,這裡是額外的約束。因為對於它的parent來說,約束已經制定好了,所以ConstrainedBox會被忽略。
我們再看下下面的程式碼:
Widget build(BuildContext context) {
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 70,
minHeight: 70,
maxWidth: 150,
maxHeight: 150,
),
child: Container(color: blue, width: 10, height: 10),
),
);
}
這裡因為使用了Center,Center會讓child來自行決定他們的大小,所以這裡的ConstrainedBox是生效的,如下:
flutter中除了ConstrainedBox,還有一個UnconstrainedBox,它的作用和ConstrainedBox是相反的,大家可以自行嘗試。
從上面的具體例子,我們可以看出,雖然我們有通用的Constraint規則,但是具體的表現還是要看不同的widget來定。
所以大家在使用widget的時候,一定要去讀一下widget的程式碼,從而加深對widget的掌握。
本文的例子:https://github.com/ddean2009/learn-flutter.git
更多內容請參考 http://www.flydean.com/13-flutter-ui-constraints/
最通俗的解讀,最深刻的乾貨,最簡潔的教學,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!