Flutter實戰(zhàn) 尺寸限制類容器

2021-03-08 10:28 更新

尺寸限制類容器用于限制容器大小,F(xiàn)lutter 中提供了多種這樣的容器,如ConstrainedBox、SizedBox、UnconstrainedBoxAspectRatio等,本節(jié)將介紹一些常用的。

#5.2.1 ConstrainedBox

ConstrainedBox用于對子組件添加額外的約束。例如,如果你想讓子組件的最小高度是80像素,你可以使用const BoxConstraints(minHeight: 80.0)作為子組件的約束。

#示例

我們先定義一個redBox,它是一個背景顏色為紅色的盒子,不指定它的寬度和高度:

  1. Widget redBox=DecoratedBox(
  2. decoration: BoxDecoration(color: Colors.red),
  3. );

我們實現(xiàn)一個最小高度為 50,寬度盡可能大的紅色容器。

  1. ConstrainedBox(
  2. constraints: BoxConstraints(
  3. minWidth: double.infinity, //寬度盡可能大
  4. minHeight: 50.0 //最小高度為50像素
  5. ),
  6. child: Container(
  7. height: 5.0,
  8. child: redBox
  9. ),
  10. )

運行效果如圖5-2所示:

圖5-2

可以看到,我們雖然將 Container 的高度設(shè)置為 5 像素,但是最終卻是 50 像素,這正是 ConstrainedBox 的最小高度限制生效了。如果將 Container 的高度設(shè)置為 80 像素,那么最終紅色區(qū)域的高度也會是 80 像素,因為在此示例中,ConstrainedBox 只限制了最小高度,并未限制最大高度。

#BoxConstraints

BoxConstraints用于設(shè)置限制條件,它的定義如下:

  1. const BoxConstraints({
  2. this.minWidth = 0.0, //最小寬度
  3. this.maxWidth = double.infinity, //最大寬度
  4. this.minHeight = 0.0, //最小高度
  5. this.maxHeight = double.infinity //最大高度
  6. })

BoxConstraints 還定義了一些便捷的構(gòu)造函數(shù),用于快速生成特定限制規(guī)則的 BoxConstraints,如BoxConstraints.tight(Size size),它可以生成給定大小的限制;const BoxConstraints.expand()可以生成一個盡可能大的用以填充另一個容器的 BoxConstraints。除此之外還有一些其它的便捷函數(shù),讀者可以查看API文檔 (opens new window)。

#5.2.2 SizedBox

SizedBox用于給子元素指定固定的寬高,如:

  1. SizedBox(
  2. width: 80.0,
  3. height: 80.0,
  4. child: redBox
  5. )

運行效果如圖5-3所示:

實際上SizedBox只是ConstrainedBox的一個定制,上面代碼等價于:

  1. ConstrainedBox(
  2. constraints: BoxConstraints.tightFor(width: 80.0,height: 80.0),
  3. child: redBox,
  4. )

BoxConstraints.tightFor(width: 80.0,height: 80.0)等價于:

  1. BoxConstraints(minHeight: 80.0,maxHeight: 80.0,minWidth: 80.0,maxWidth: 80.0)

而實際上ConstrainedBoxSizedBox都是通過RenderConstrainedBox來渲染的,我們可以看到ConstrainedBoxSizedBoxcreateRenderObject()方法都返回的是一個RenderConstrainedBox對象:

  1. @override
  2. RenderConstrainedBox createRenderObject(BuildContext context) {
  3. return new RenderConstrainedBox(
  4. additionalConstraints: ...,
  5. );
  6. }

#5.2.3 多重限制

如果某一個組件有多個父級ConstrainedBox限制,那么最終會是哪個生效?我們看一個例子:

  1. ConstrainedBox(
  2. constraints: BoxConstraints(minWidth: 60.0, minHeight: 60.0), //父
  3. child: ConstrainedBox(
  4. constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),//子
  5. child: redBox,
  6. )
  7. )

上面我們有父子兩個ConstrainedBox,他們的限制條件不同,運行后效果如圖5-4所示:

最終顯示效果是寬 90,高 60,也就是說是子ConstrainedBoxminWidth生效,而minHeight是父ConstrainedBox生效。單憑這個例子,我們還總結(jié)不出什么規(guī)律,我們將上例中父子限制條件換一下:

  1. ConstrainedBox(
  2. constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),
  3. child: ConstrainedBox(
  4. constraints: BoxConstraints(minWidth: 60.0, minHeight: 60.0),
  5. child: redBox,
  6. )
  7. )

運行效果如圖5-5所示:

最終的顯示效果仍然是 90,高 60,效果相同,但意義不同,因為此時minWidth生效的是父ConstrainedBox,而minHeight是子ConstrainedBox生效。

通過上面示例,我們發(fā)現(xiàn)有多重限制時,對于minWidthminHeight來說,是取父子中相應(yīng)數(shù)值較大的。實際上,只有這樣才能保證父限制與子限制不沖突。

思考題:對于maxWidthmaxHeight,多重限制的策略是什么樣的呢?

#5.2.4 UnconstrainedBox

UnconstrainedBox不會對子組件產(chǎn)生任何限制,它允許其子組件按照其本身大小繪制。一般情況下,我們會很少直接使用此組件,但在"去除"多重限制的時候也許會有幫助,我們看下下面的代碼:

  1. ConstrainedBox(
  2. constraints: BoxConstraints(minWidth: 60.0, minHeight: 100.0), //父
  3. child: UnconstrainedBox( //“去除”父級限制
  4. child: ConstrainedBox(
  5. constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),//子
  6. child: redBox,
  7. ),
  8. )
  9. )

上面代碼中,如果沒有中間的UnconstrainedBox,那么根據(jù)上面所述的多重限制規(guī)則,那么最終將顯示一個 90×100 的紅色框。但是由于UnconstrainedBox “去除”了父ConstrainedBox的限制,則最終會按照子ConstrainedBox的限制來繪制redBox,即 90×20:

但是,讀者請注意,UnconstrainedBox對父組件限制的“去除”并非是真正的去除:上面例子中雖然紅色區(qū)域大小是 90×20,但上方仍然有80的空白空間。也就是說父限制的minHeight(100.0)仍然是生效的,只不過它不影響最終子元素redBox的大小,但仍然還是占有相應(yīng)的空間,可以認(rèn)為此時的父ConstrainedBox是作用于子UnconstrainedBox上,而redBox只受子ConstrainedBox限制,這一點請讀者務(wù)必注意。

那么有什么方法可以徹底去除父ConstrainedBox的限制嗎?答案是否定的!所以在此提示讀者,在定義一個通用的組件時,如果要對子組件指定限制,那么一定要注意,因為一旦指定限制條件,子組件如果要進(jìn)行相關(guān)自定義大小時將可能非常困難,因為子組件在不更改父組件的代碼的情況下無法徹底去除其限制條件。

在實際開發(fā)中,當(dāng)我們發(fā)現(xiàn)已經(jīng)使用SizedBoxConstrainedBox給子元素指定了寬高,但是仍然沒有效果時,幾乎可以斷定:已經(jīng)有父元素已經(jīng)設(shè)置了限制!舉個例子,如 Material 組件庫中的AppBar(導(dǎo)航欄)的右側(cè)菜單中,我們使用SizedBox指定了 loading 按鈕的大小,代碼如下:

  1. AppBar(
  2. title: Text(title),
  3. actions: <Widget>[
  4. SizedBox(
  5. width: 20,
  6. height: 20,
  7. child: CircularProgressIndicator(
  8. strokeWidth: 3,
  9. valueColor: AlwaysStoppedAnimation(Colors.white70),
  10. ),
  11. )
  12. ],
  13. )

上面代碼運行后,效果如圖5-7所示:

圖5-6

我們會發(fā)現(xiàn)右側(cè) loading 按鈕大小并沒有發(fā)生變化!這正是因為AppBar中已經(jīng)指定了actions按鈕的限制條件,所以我們要自定義 loading 按鈕大小,就必須通過UnconstrainedBox來“去除”父元素的限制,代碼如下:

  1. AppBar(
  2. title: Text(title),
  3. actions: <Widget>[
  4. UnconstrainedBox(
  5. child: SizedBox(
  6. width: 20,
  7. height: 20,
  8. child: CircularProgressIndicator(
  9. strokeWidth: 3,
  10. valueColor: AlwaysStoppedAnimation(Colors.white70),
  11. ),
  12. ),
  13. )
  14. ],
  15. )

運行后效果如圖5-8所示:

圖5-8

生效了!

#5.2.4 其它尺寸限制類容器

除了上面介紹的這些常用的尺寸限制類容器外,還有一些其他的尺寸限制類容器,比如AspectRatio,它可以指定子組件的長寬比、LimitedBox 用于指定最大寬高、FractionallySizedBox 可以根據(jù)父容器寬高的百分比來設(shè)置子組件寬高等,由于這些容器使用起來都比較簡單,我們便不再贅述,讀者可以自行了解。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號