Flutter-详解布局(单子组件布局控件)

DEMO

单子组件布局控件

1. Container

  • 说明: 最常用的布局 Widget,可以包含一个子Widget,并可以设置 padding、margin、边框、背景等

  • 规则: 如果没有子 Widget,Container 会尽可能大;如果有子 Widget,则根据子 Widget 和自身约束调整大小

  • 注意: 在没有约束的情况下,Container会尽可能大(比如占满整个屏幕);在有约束的情况下(如父Widget是Column),Container如果没有子Widget,则会收缩到没有大小

  • 推荐: 作为其他Widget的容器,用于装饰或设置间距

Container(
    padding: const EdgeInsets.all(8.0),
    margin: const EdgeInsets.all(16.0),
    decoration: BoxDecoration(
        color: Colors.blue,
        borderRadius: BorderRadius.circular(8.0),
    ),
    child: const Text('Hello World'),
)
Container页面

2. Padding

  • 说明: 给子Widget设置内边距

  • 规则: 只有一个子Widget

  • 注意: 与Container的padding不同,Padding是一个独立的Widget

  • 推荐: 当需要内边距但不需要Container的其他装饰时使用

Container(
  decoration: BoxDecoration(
    color: Colors.blue,
    borderRadius: BorderRadius.circular(12),
  ),
  child: const Padding(
    padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
    child: Text(
      "Flutter Padding 背景颜色示例",
      style: TextStyle(color: Colors.white),
    ),
  ),
)

Padding

3. Align

  • 说明: 控制子Widget在父Widget中的对齐方式

  • 规则: 通过alignment属性设置对齐方式(如Alignment.center)

  • 注意: 如果父Widget没有约束,Align会尽可能大;如果有约束,则根据约束调整大小,并将子Widget对齐

  • 推荐: 用于精确控制子Widget的位置

Container(
  height: 200,
  width: 200,
  color: Colors.grey,
  child: Align(
    alignment: Alignment.bottomRight,
    child: Container(width: 50, height: 50, color: Colors.red),
  ),
)
Align

4. Center

  • 说明: 用于将子组件在父组件中水平和垂直居中显示(是Align(alignment: Alignment.center)的简写),Center 组件继承自 Align,因此它本质上是一个简化版的 Align,专门用于居中布局

  • 规则: 如果 Center 没有子组件且父容器提供无界约束(unbounded),则 Center 会尽可能缩小自身尺寸,如果父容器提供有界约束(bounded),则 Center 会扩展到父容器的大小。有子组件时,Center 的尺寸会根据子组件的大小和父容器的约束动态调整。

如果设置了 widthFactor 或 heightFactor,子组件的尺寸会按比例缩放(例如 widthFactor: 2 会使子组件宽度翻倍)

  • 注意: widthFactor 和 heightFactor用于调整子组件的宽度和高度比例,避免嵌套过多层级,如果父容器限制了尺寸(如 SizedBox),需确保 Center 的子组件尺寸在约束范围内

  • 推荐: 快速居中单个组件,与复杂布局结合,响应式布局

Center(
  child: Container(
    width: 200,
    height: 100,
    color: Colors.blue,
    child: const Text(
      "居中内容",
      style: TextStyle(color: Colors.white),
    ),
  ),
)
Center

5. AspectRatio

  • 说明: 强制子Widget保持指定的宽高比

  • 规则: 需要设置aspectRatio属性(宽/高)

  • 注意: 父Widget必须提供约束,否则无法计算

  • 推荐: 用于需要固定宽高比的场景,如播放器

AspectRatio(
  aspectRatio: 16 / 9,
  child: Container(color: Colors.blue),
)
AspectRatio

6. ConstrainedBox

  • 说明: 对子Widget施加额外的约束(BoxConstraints)

  • 规则: 可以设置最小、最大宽高

  • 注意: 如果子Widget本身有约束,可能会冲突,此时以更紧的约束为准

  • 推荐: 用于需要限制子Widget大小的情况

ConstrainedBox(
  constraints: const BoxConstraints(
    minWidth: 100,
    maxWidth: 200,
    minHeight: 50,
    maxHeight: 100,
  ),
  child: Container(color: Colors.red),
)
ConstrainedBox

7. UnconstrainedBox

  • 说明: 解除父容器的约束,允许子控件按照自身大小绘制,然后根据实际大小再约束

  • 规则: 子组件,其尺寸不会受到UnconstrainedBox的约束,若子组件尺寸超过父容器区域,Debug模式下会显示黄色溢出警告(Release模式会裁剪),若父级有多个约束组件(如嵌套的ConstrainedBox),UnconstrainedBox只能突破直接父级的约束,无法突破更高层约束

  • 注意: constrainedAxis:null(默认):完全解除约束 / Axis.horizontal :仅水平方向解除约束,垂直方向仍受父级限制 / Axis.vertical :仅垂直方向解除约束,水平方向受限制,过度使用可能导致布局计算复杂化,建议仅在必要时使用

  • 推荐: 适用于需要突破父容器约束的场景,例如在ListView或AppBar中保持子组件原始尺寸

ListView(
  children: [
    // 原始Container被拉伸至屏幕宽度 
    Container(width: 200, height: 100, color: Colors.red), 
    
    // 使用UnconstrainedBox保持原始尺寸
    UnconstrainedBox(
      child: Container(width: 200, height: 100, color: Colors.blue), 
    ),
  ],
)
UnconstrainedBox

8. SizedBox

  • 说明: 可以指定固定大小的盒子,也可以用于设置间隔

  • 规则: 如果指定了width和height,则强制子Widget使用该大小(如果子Widget有约束,则可能会强制调整)

  1. SizedBox.shrink() 零尺寸占位符
  2. SizedBox.expand() 扩展填充占位符
  3. SizedBox.fromSize() 指定尺寸占位符
  • 注意: 当没有子Widget时,SizedBox会占据指定大小的空间;有子Widget时,则强制子Widget大小为指定大小

  • 推荐: 用于固定尺寸的盒子或间隔(如SizedBox(width: 10))

SizedBox(
  width: 100,
  height: 100,
  child: Container(color: Colors.green),
)
SizedBox

9. FractionallySizedBox

  • 说明: 子Widget的大小相对于父Widget的百分比

  • 规则: 需要设置widthFactor和heightFactor(0.0到1.0)

  • 注意: 父Widget必须提供约束,否则无法计算百分比

  • 推荐: 用于需要相对父容器百分比大小的场景

Container(
  width: 200,
  height: 200,
  color: Colors.blue,
  child: FractionallySizedBox(
    widthFactor: 0.5,
    heightFactor: 0.5,
    child: Container(color: Colors.red),
  ),
)
FractionallySizedBox

10. Transform

  • 说明: 对子Widget进行矩阵变换(平移、旋转、缩放等)

  • 规则: 变换不影响布局,变换是在布局之后进行的,所以可能会超出父Widget区域

  • 注意: 变换后可能会超出父Widget范围,导致被裁剪(可以使用Clip.none避免)

  • 推荐: 用于需要变换的场景,如旋转一个图标

Transform.rotate(
  angle: 3.14 / 4, // 45度
  child: Container(width: 100, height: 100, color: Colors.blue),
)
Transform

11. Baseline

  • 说明: 根据子Widget的基线对齐(常用于文本), Baseline 的对齐方式有两种类型:

alphabetic: 对齐字母底部基线(适用于英文等拉丁文字)

ideographic: 对齐表意文字基线(适用于中文、日文等)

  • 规则: 需要设置baseline和baselineType(如TextBaseline.alphabetic)

  • 注意: 需要子Widget有基线(如Text),否则无效

  • 推荐: 尤其适用于文字排版场景,处理混合文字(如中英文)时,通过baselineType区分基线类型,避免排版错乱

const Row(
  children: [
    Baseline(
      baseline: 50.0,
      baselineType: TextBaseline.alphabetic,
      child: Text('Hello', style: TextStyle(fontSize: 20)),
    ),
    Baseline(
      baseline: 50.0,
      baselineType: TextBaseline.alphabetic,
      child: Text('World', style: TextStyle(fontSize: 30)),
    ),
  ],
)
Baseline

12. FittedBox

  • 说明: 对子Widget进行缩放和位置调整,以使其适应可用空间

  • 规则: 通过fit属性设置适应方式(如BoxFit.contain)

  • 注意: 如果子Widget没有约束,可能会出现问题

  • 推荐: 用于需要缩放的场景,如保持图片比例并适应容器

Container(
  width: 200,
  height: 100,
  color: Colors.amber,
  child: FittedBox(
    fit: BoxFit.contain,
    child: Image.network(
        'https://upload-images.jianshu.io/upload_images/1976231-cb638ee25dbc7368.png'),
  ),
)
FittedBox

13. OverflowBox

  • 说明: 允许子Widget超出父Widget的约束,从而在父容器之外显示

  • 规则: 设置自己的约束,子Widget可以突破父Widget的约束

  • 注意: 可能导致布局溢出(无警告),使用时需注意

  • 推荐: 在需要突破约束时使用,但需谨慎

Container(
  color: Colors.green,
  width: 200.0,
  height: 200.0,
  padding: const EdgeInsets.all(50.0),
  child: OverflowBox(
    alignment: Alignment.topLeft,
    maxWidth: 400.0,
    maxHeight: 400.0,
    child: Container(
      color: Colors.blueGrey,
      width: 300.0,
      height: 300.0,
    ),
  ),
)
OverflowBox

14. LimitedBox

  • 说明: 一个用于限制子组件最大尺寸的布局组件,当父Widget没有约束时,限制子Widget的最大宽高

  • 规则: 在无约束时生效(如在ListView中,ListView沿着主轴方向有约束,但交叉轴方向无约束,此时在交叉轴方向使用LimitedBox可以限制最大宽高)

  • 注意: 在父Widget有约束时无效

  • 推荐: 在ListView中限制交叉轴方向的大小

Row(
  children: [
    Container(
      color: Colors.grey,
      width: 100.0,
    ),
    LimitedBox(
      maxWidth: 150.0,
      maxHeight: 150.0,
      child: Container(
        color: Colors.lightGreen,
        width: 250.0,
        height: 250.0,
      ),
    ),
  ],
)
LimitedBox

15. IntrinsicWidth/IntrinsicHeight

  • 说明: 调整子Widget到其内部内容的高度或宽度(有性能问题,慎用)

  • 规则: 迫使子Widget计算其内部内容的最大高度或宽度,并调整其他子Widget到相同高度或宽度

  • 注意: 性能差,因为需要遍历子Widget两次(一次测量,一次布局)

  • 推荐: 尽量避免使用,寻找其他布局方式替代。如果必须使用,注意性能影响

Column(
  mainAxisAlignment: MainAxisAlignment.start,
  children: [
    IntrinsicWidth(
      stepWidth: 100,
      child: Container(
        color: Colors.blue,
        child: Center(
          child: Container(
            color: Colors.red,
            width: 50,
            height: 50,
          ),
        ),
      ),
    ),
  ],
)
IntrinsicWidth

16. CustomSingleChildLayout/CustomMultiChildLayout

  • 说明: 使用自定义的布局代理进行布局,可以实现复杂的布局效果,CustomSingleChildLayout 是一个用于控制单个子组件布局的组件,CustomMultiChildLayout 是一个用于控制多个子组件布局的组件

  • 规则: 需要自定义LayoutDelegate,SingleChildLayoutDelegate 来实现布局逻辑。该组件适用于需要对单个子组件进行复杂或非常规布局的场景,例如需要精确控制子组件的位置或尺寸时,MultiChildLayoutDelegate 来实现布局逻辑,适用于需要对多个子组件进行复杂布局的场景

  • 注意: 相对复杂,需要自己实现布局逻辑

  • 推荐:当其他布局Widget无法满足需求时使用,自定义的网格布局、层叠布局

CustomSingleChildLayout(
  delegate: _MyDelegate(),
  child: Container(color: Colors.blue), 
)
 
class _MyDelegate extends SingleChildLayoutDelegate {
  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    return constraints.loosen();  // 解除子组件约束 
  }
  
  @override
  Offset getPositionForChild(Size size, Size childSize) {
    return Offset(size.width/2,  0); // 顶部居中
  }
  
  @override
  bool shouldRelayout(covariant SingleChildLayoutDelegate oldDelegate) {
    // TODO: implement shouldRelayout
    throw UnimplementedError();
  }
}
CustomSingleChildLayout
Container(
  width: 200.0,
  height: 100.0,
  color: Colors.yellow,
  child: CustomMultiChildLayout(
    delegate: TestLayoutDelegate(),
    children: <Widget>[
      LayoutId(
        id: TestLayoutDelegate.title,
        child: Container(
          color: Colors.red,
          child: const Text('Title'),
        ),
      ),
      LayoutId(
        id: TestLayoutDelegate.description,
        child: Container(
          color: Colors.green,
          child: const Text('Description'),
        ),
      ),
    ],
  ),
)

class TestLayoutDelegate extends MultiChildLayoutDelegate {
  static const String title = 'title';
  static const String description = 'description';

  @override
  void performLayout(Size size) {
    final BoxConstraints constraints = BoxConstraints(maxWidth: size.width);
    final Size titleSize = layoutChild(title, constraints);
    positionChild(title, const Offset(0.0, 0.0));
    final double descriptionY = titleSize.height;
    layoutChild(description, constraints);
    positionChild(description, Offset(0.0, descriptionY));
  }

  @override
  bool shouldRelayout(TestLayoutDelegate oldDelegate) => false;
}
CustomMultiChildLayout

17. Placeholder

  • 说明: 主要用于在开发过程中快速构建页面骨架,加速页面流程的运行。它可以在布局中占位,帮助开发者快速预览页面结构。Placeholder 的大小默认适合其容器,若位于无界空间(unbounded space),则根据 fallbackWidth 和 fallbackHeight 调整大小。Placeholder 支持自定义颜色、线条宽度、fallbackHeight 和 fallbackWidth

  • 规则: 可以在 Row 或 Column 中使用 Placeholder,但需要通过 fallbackHeight 和 fallbackWidth 限定大小,在无界空间中,可以使用 fallbackWidth 和 fallbackHeight 来限定占位符的大小

  • 注意: 虽然 Placeholder 是一个简单的占位符,但在复杂的布局中过多使用可能会影响性能,因此应合理使用

  • 推荐: 在页面开发初期,可以使用 Placeholder 来快速构建页面骨架,帮助开发者快速预览页面结构

const Center(
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      SizedBox(
        height: 100,
        child: Row(
          children: [
            Placeholder(
              fallbackWidth: 100,
              color: Colors.green,
              strokeWidth: 10,
            ),
          ],
        ),
      ),
      SizedBox(
        width: 100,
        child: Column(
          children: [
            Placeholder(
              fallbackHeight: 100,
              color: Colors.green,
              strokeWidth: 10,
            ),
          ],
        ),
      ),
    ],
  ),
);
Placeholder

因为网站字数限制,只能分系列了,需要一次性看完请去这里
Flutter-详解布局(核心布局控件)
Flutter-详解布局(弹性和层叠布局辅助控件)
Flutter-详解布局(滚动和Sliver系列布局控件)
Flutter-详解布局(响应式和平台适配及特殊布局控件)
需要代码去这里DEMO

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容