Flutter的盒子約束

由Expanded widget引起的思考

設計稿以下html

flutter效果圖

佈局widget分解api

flutter效果圖

很常見的一種佈局方式:Column的子widget中包含ListViewide

@override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        ListView.builder(
          itemCount: 30,
          itemBuilder: (BuildContext context, int index) {
            return ListTile(
              title: Text("標題$index"),
            );
          },
        ),
      ],
    );
  }

固然這樣僅僅這樣寫,在手機屏幕上會看到一片空白,若是是debug模式,則會在控制檯中看到以下報錯佈局

════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: RenderRepaintBoundary#e7255 relayoutBoundary=up2 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1687 pos 12: 'hasSize'
The relevant error-causing widget was
Columnflex

從報錯信息能夠得知是Column widget出錯了,RenderBox未正確佈局等等。ui

正確的寫法this

@override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Expanded(
          child: ListView.builder(
            itemCount: 30,
            itemBuilder: (BuildContext context, int index) {
              return ListTile(
                title: Text("標題$index"),
              );
            },
          ),
        ),
      ],
    );
  }

在ListView外層嵌套一個Expanded widget翻譯

Expanded widget做用是給子 widget 分配剩餘的空間,也就是隻要給ListView指定高度便可。固然也就能夠在ListView外層嵌套一個限定高度的Container widget。debug

Flutter盒子

In Flutter, widgets are rendered by their underlying RenderBox objects. Render boxes are given constraints by their parent, and size themselves within those constraints. Constraints consist of minimum and maximum widths and heights; sizes consist of a specific width and height.
Generally, there are three kinds of boxes, in terms of how they handle their constraints:設計

  • Those that try to be as big as possible. For example, the boxes used by Center and ListView.
  • Those that try to be the same size as their children. For example, the boxes used by Transform and Opacity
  • Those that try to be a particular size. For example, the boxes used by Image and Text.

這是Flutter官網關於flutter 盒子約束的一段話。在Flutter中,widget由其底層的RenderBox對象渲染。 渲染框由它們的父級給出約束,而且在這些約束下調整自身大小。約束由最小寬高、最大寬高組成(這裏是我我的見解,Flutter中文網翻譯是,約束由最小寬度、最大寬度和高度組成 ); 尺寸由特定的寬度和高度組成。

按照寬高約束條件來劃分,flutter 盒子有三類:

  • 無限制邊界(在某一個方向,好比縱向滾動那麼寬度就是受限制的而高度無邊界,並非寬高都任意大),例如Center和ListView widget
  • 由子widget的寬高決定了本身的邊界,如 Transform 和 Opacity
  • 有肯定的寬高大小,如 Image和Text widget

而下面這句話就恰好解釋了上面那個報錯

A box that tries to be as big as possible won’t function usefully when given an unbounded constraint and, in debug mode, such a combination throws an exception that points to this file.

The most common cases where a render box finds itself with unbounded constraints are within flex boxes (Row and Column), and within scrollable regions (ListView and other ScrollView subclasses).

上面那個例子中,Column在縱向上面是無限制的,而ListView在其滾動方向上也是無限制。而上面這句話也解釋了,一個自己試圖佔用儘量大的渲染盒在給定無邊界約束時不會有用,在debug模式下,會拋出異常

因此當咱們給ListView外層嵌套了Expanded或者限高的Container,避免了一個不限制高度的widget直接被嵌套於另一個不限高的widget中,在VSCode終端直接運行flutter run 控制檯是沒有任何打印信息,只有在debug模式下,控制檯會打印異常。

總結

開發中使用debug模式,不只能夠斷點調試,更能在控制檯看到異常信息。技術都有必定的共通性,雖然flutter一切基於widget,可是在盒子的寬高方面也如同CSS ,能夠繼承自父類,也能夠自定義寬高,或者由子類寬高撐起來。

參考文檔

https://flutter.dev/docs/development/ui/layout/box-constraints
https://flutterchina.club/layout/

相關文章
相關標籤/搜索