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

2021-03-08 10:28 更新

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

#5.2.1 ConstrainedBox

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

#示例

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

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

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

ConstrainedBox(
  constraints: BoxConstraints(
    minWidth: double.infinity, //寬度盡可能大
    minHeight: 50.0 //最小高度為50像素
  ),
  child: Container(
      height: 5.0, 
      child: redBox 
  ),
)

運(yùn)行效果如圖5-2所示:

圖5-2

可以看到,我們雖然將 Container 的高度設(shè)置為 5 像素,但是最終卻是 50 像素,這正是 ConstrainedBox 的最小高度限制生效了。如果將 Container 的高度設(shè)置為 80 像素,那么最終紅色區(qū)域的高度也會(huì)是 80 像素,因?yàn)樵诖耸纠?,ConstrainedBox 只限制了最小高度,并未限制最大高度。

#BoxConstraints

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

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

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

#5.2.2 SizedBox

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

SizedBox(
  width: 80.0,
  height: 80.0,
  child: redBox
)

運(yùn)行效果如圖5-3所示:

實(shí)際上SizedBox只是ConstrainedBox的一個(gè)定制,上面代碼等價(jià)于:

ConstrainedBox(
  constraints: BoxConstraints.tightFor(width: 80.0,height: 80.0),
  child: redBox, 
)

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

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

而實(shí)際上ConstrainedBoxSizedBox都是通過(guò)RenderConstrainedBox來(lái)渲染的,我們可以看到ConstrainedBoxSizedBoxcreateRenderObject()方法都返回的是一個(gè)RenderConstrainedBox對(duì)象:

@override
RenderConstrainedBox createRenderObject(BuildContext context) {
  return new RenderConstrainedBox(
    additionalConstraints: ...,
  );
}

#5.2.3 多重限制

如果某一個(gè)組件有多個(gè)父級(jí)ConstrainedBox限制,那么最終會(huì)是哪個(gè)生效?我們看一個(gè)例子:

ConstrainedBox(
    constraints: BoxConstraints(minWidth: 60.0, minHeight: 60.0), //父
    child: ConstrainedBox(
      constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),//子
      child: redBox,
    )
)

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

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

ConstrainedBox(
    constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),
    child: ConstrainedBox(
      constraints: BoxConstraints(minWidth: 60.0, minHeight: 60.0),
      child: redBox,
    )
)

運(yùn)行效果如圖5-5所示:

最終的顯示效果仍然是 90,高 60,效果相同,但意義不同,因?yàn)榇藭r(shí)minWidth生效的是父ConstrainedBox,而minHeight是子ConstrainedBox生效。

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

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

#5.2.4 UnconstrainedBox

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

ConstrainedBox(
    constraints: BoxConstraints(minWidth: 60.0, minHeight: 100.0),  //父
    child: UnconstrainedBox( //“去除”父級(jí)限制
      child: ConstrainedBox(
        constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),//子
        child: redBox,
      ),
    )
)

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

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

那么有什么方法可以徹底去除父ConstrainedBox的限制嗎?答案是否定的!所以在此提示讀者,在定義一個(gè)通用的組件時(shí),如果要對(duì)子組件指定限制,那么一定要注意,因?yàn)橐坏┲付ㄏ拗茥l件,子組件如果要進(jìn)行相關(guān)自定義大小時(shí)將可能非常困難,因?yàn)樽咏M件在不更改父組件的代碼的情況下無(wú)法徹底去除其限制條件。

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

 AppBar(
   title: Text(title),
   actions: <Widget>[
         SizedBox(
             width: 20, 
             height: 20,
             child: CircularProgressIndicator(
                 strokeWidth: 3,
                 valueColor: AlwaysStoppedAnimation(Colors.white70),
             ),
         )
   ],
)

上面代碼運(yùn)行后,效果如圖5-7所示:

圖5-6

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

AppBar(
  title: Text(title),
  actions: <Widget>[
      UnconstrainedBox(
            child: SizedBox(
              width: 20,
              height: 20,
              child: CircularProgressIndicator(
                strokeWidth: 3,
                valueColor: AlwaysStoppedAnimation(Colors.white70),
              ),
          ),
      )
  ],
)

運(yùn)行后效果如圖5-8所示:

圖5-8

生效了!

#5.2.4 其它尺寸限制類容器

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

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)