IntrinsicWidth 简单使用 | Flutter

1,418 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第 6 天,点击查看活动详情

什么用

A widget that sizes its child to the child's maximum intrinsic width

先看代码中对组件的注释,让子组件的宽度为子组件的最大内在宽度。也就是当希望一个组件没有固定的大小时,让这个组件自己测量,得到一个最大的宽度。

场景 案例

希望达到的效果如下,title 和 content 宽度相同

编写代码如下

Widget buildBearWidget(int i) {

  return Padding(

    padding: EdgeInsets.all(8.0),

    child: Container(

      color: Colors.white,

      child: Column(

        children: [

          Container(

            color: Colors.grey,

            child: Text('title ' * i),

          ),

          Container(

            color: Colors.indigoAccent,

            child: ConstrainedBox(

                constraints: const BoxConstraints(

                  minHeight: 50,

                  minWidth: 50,

                ),

                child: Text('content ' * i)),

          ),

        ],

      ),

    ),

  );

}

实际运行效果为

图中 灰色背景为 title,蓝色背景为 content

可以看到 title 和 content 的宽度不一致,如果希望 title 和 content 宽度一致,那么尝试设置 两个widget 的宽度都与 父相同,添加

width: double.infinity

得到的效果为

Title 和 content 的宽度相同了,也和父widget宽度相同了,但是父 widget 也被撑满了更高的一层widget。

父widget 和 期待的效果不同,需要父 widget 为 子 widget 的最大宽度。

效果符合预期了

定义



 /// A widget that sizes its child to the child's maximum intrinsic width.

 /// 让孩子的大小为子组件的最大内在宽度的组件

///

 /// This class is useful, for example, when unlimited width is available and

 /// you would like a child that would otherwise attempt to expand infinitely to

 /// instead size itself to a more reasonable width.

 ///

 /// 什么时候有用:未限制宽度,一个字组件试图扩展到无限宽度,

 /// 但是你让子组件的大小为一个更合适的宽度

 ///

 /// The constraints that this widget passes to its child will adhere to the

 /// parent's constraints, so if the constraints are not large enough to satisfy

 /// the child's maximum intrinsic width, then the child will get less width

 /// than it otherwise would. Likewise, if the minimum width constraint is

 /// larger than the child's maximum intrinsic width, the child will be given

 /// more width than it otherwise would.

 ///

 /// If [stepWidth] is non-null, the child's width will be snapped to a multiple

 /// of the [stepWidth]. Similarly, if [stepHeight] is non-null, the child's

 /// height will be snapped to a multiple of the [stepHeight].

 ///

 /// This class is relatively expensive, because it adds a speculative layout

 /// pass before the final layout phase. Avoid using it where possible. In the

 /// worst case, this widget can result in a layout that is O(N²) in the depth of

 /// the tree.



这个类相对昂贵,因为他在最终布局前添加了推测布局传递,了最差情况下可能会生成 O(N^2)深度的 layout 树

注意事项

耗费性能 - 原因未抽时间分析,目前体验无卡顿

原理:

RenderIntrinsicWidth 中 获取子 widget 的内在宽度



Size _computeSize({required ChildLayouter layoutChild, required BoxConstraints constraints}) {

  if (child != null) {

    if (!constraints.hasTightWidth) {

      final double width = child!.getMaxIntrinsicWidth(constraints.maxHeight);

      assert(width.isFinite);

      constraints = constraints.tighten(width: _applyStep(width, _stepWidth));

    }

    if (_stepHeight != null) {

      final double height = child!.getMaxIntrinsicHeight(constraints.maxWidth);

      assert(height.isFinite);

      constraints = constraints.tighten(height: _applyStep(height, _stepHeight));

    }

    return layoutChild(child!, constraints);

  } else {

    return constraints.smallest;

  }

}