Skip to content

布局概览与基础容器

Flutter 的布局系统基于父约束子模型:父组件告诉子组件「你有多少空间」,子组件决定「我用多少空间」。理解这个模型,是掌握 Flutter 布局的关键。

布局核心原理

约束模型

Flutter 布局过程分两步:

  1. 向下传递约束:父组件给子组件一组约束(最小/最大宽度、最小/最大高度)
  2. 向上报告尺寸:子组件在约束范围内决定自己的尺寸,报告给父组件
父组件:"你的宽度必须在 100~300 之间,高度必须在 50~600 之间"
子组件:"好的,我选择 200×100"
父组件:"收到,你在 (x, y) 位置"

常见布局组件分类

类别组件作用
单子组件Container、Padding、Center、Align、SizedBox包裹一个子组件,添加装饰/间距/对齐
多子组件Column、Row、Stack、Wrap排列多个子组件
滚动组件ListView、GridView、SingleChildScrollView内容超出屏幕时可滚动

Container — 万能容器

Container 是最常用的组件,它本身没有外观,通过组合装饰、内边距、尺寸等属性来构建视觉效果。

常用属性

dart
Container({
  Key? key,
  AlignmentGeometry? alignment,   // 子组件对齐方式
  EdgeInsetsGeometry? padding,     // 内边距
  Color? color,                   // 背景色
  Decoration? decoration,          // 装饰(边框、圆角、渐变等)
  Decoration? foregroundDecoration, // 前景装饰
  double? width,                   // 宽度
  double? height,                  // 高度
  BoxConstraints? constraints,    // 约束
  EdgeInsetsGeometry? margin,     // 外边距
  Matrix4? transform,             // 变换
  Widget? child,                  // 子组件
  Clip clipBehavior = Clip.none,  // 裁剪方式
})

基本用法

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(home: ContainerExamples()));
}

class ContainerExamples extends StatelessWidget {
  const ContainerExamples({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Container 示例')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          // 带背景色和内边距
          // ─── ★ Container 基本用法 ──────────────
          Container(
            color: Colors.blue,
            padding: const EdgeInsets.all(16),
            child: const Text('Hello', style: TextStyle(color: Colors.white)),
          ),
          // ─── ☆ Container 基本用法 ──────────────
          const SizedBox(height: 16),

          // 带圆角和边框(必须用 decoration,不能同时设 color)
          Container(
            padding: const EdgeInsets.all(16),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(12),
              border: Border.all(color: Colors.grey),
              boxShadow: [
                BoxShadow(color: Colors.black26, blurRadius: 4, offset: const Offset(0, 2)),
              ],
            ),
            child: const Text('Card'),
          ),
          const SizedBox(height: 16),

          // 固定尺寸
          Container(
            width: 200,
            height: 100,
            color: Colors.amber,
            child: const Center(child: Text('200×100')),
          ),
        ],
      ),
    );
  }
}

Container 的尺寸规则

条件行为
child,无尺寸约束跟子组件一样大
child,有尺寸约束使用约束的尺寸
child,无尺寸约束尽量大(填满父组件)
child,有尺寸约束使用约束的尺寸

注意

colordecoration 不能同时设置。如果需要圆角、边框、阴影等装饰,统一用 decoration 中的 color


SizedBox — 固定尺寸

SizedBox 是最简单的尺寸控制组件,用于给子组件指定固定尺寸,或作为间距占位。

基本用法

dart
// 固定尺寸
SizedBox(
  width: 100,
  height: 100,
  child: Container(color: Colors.blue),
)

// 只约束宽度(高度随内容)
SizedBox(width: 200, child: const Text('xxx'))

// 作为间距使用(无 child)
const SizedBox(height: 16)  // 垂直间距 16
const SizedBox(width: 8)    // 水平间距 8

SizedBox 变体

dart
SizedBox.expand()            // 尽可能大
SizedBox.shrink()            // 尽可能小(0×0)
SizedBox.square(dimension: 50)  // 正方形 50×50

建议

在 Row / Column 中用 SizedBox 做间距,比 Padding 更直观:

dart
import 'package:flutter/material.dart';

class SpacingExample extends StatelessWidget {
  const SpacingExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('第一行'),
            const SizedBox(height: 16),
            const Text('第二行'),
          ],
        ),
      ),
    );
  }
}

Padding — 内边距

Padding 专门用于给子组件添加内边距。

基本用法

dart
import 'package:flutter/material.dart';

class PaddingExamples extends StatelessWidget {
  const PaddingExamples({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          // 四周 16
          Padding(
            padding: const EdgeInsets.all(16),
            child: Container(color: Colors.blue[100], child: const Text('all(16)')),
          ),
          const SizedBox(height: 8),

          // 水平16,垂直8
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Container(color: Colors.green[100], child: const Text('symmetric')),
          ),
          const SizedBox(height: 8),

          // 只设左边和上边
          Padding(
            padding: const EdgeInsets.only(left: 16, top: 8),
            child: Container(color: Colors.orange[100], child: const Text('only')),
          ),
          const SizedBox(height: 8),

          // 左上右下
          Padding(
            padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
            child: Container(color: Colors.purple[100], child: const Text('fromLTRB')),
          ),
        ],
      ),
    );
  }
}

EdgeInsets 常用构造函数

构造函数说明示例
EdgeInsets.all(n)四周相同all(16) → 上下左右 16
EdgeInsets.symmetric(h, v)水平/垂直对称symmetric(horizontal: 16, vertical: 8)
EdgeInsets.only(l, t, r, b)只设指定边only(left: 16)
EdgeInsets.fromLTRB(l, t, r, b)左上右下分别设置fromLTRB(16, 8, 16, 8)

Padding vs Container 的 padding

dart
import 'package:flutter/material.dart';

class PaddingVsContainer extends StatelessWidget {
  const PaddingVsContainer({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          // 方式一:Padding 组件(推荐,语义清晰)
          Padding(
            padding: const EdgeInsets.all(16),
            child: Container(color: Colors.blue[100], child: const Text('Padding')),
          ),
          // 方式二:Container 的 padding
          Container(
            padding: const EdgeInsets.all(16),
            color: Colors.green[100],
            child: const Text('Container'),
          ),
        ],
      ),
    );
  }
}

建议

如果只需要添加内边距,Padding 而非 Container——语义更明确,性能更好。


布局调试技巧

查看布局边界

MaterialApp 中开启调试模式:

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
    debugShowCheckedModeBanner: false,
    showPerformanceOverlay: false,
    home: Scaffold(body: Center(child: Text('调试布局'))),
  ));
  // 在代码中随时调用:
  // debugPaintSizeEnabled = true;  // 显示布局边界
}

使用 Flutter Inspector

在 VS Code / Android Studio 中使用 Flutter Inspector 可视化查看 Widget 树和布局约束。

常见布局问题

问题原因解决
组件不显示未设置尺寸或颜色添加 colorwidth/height 调试
溢出黄条内容超出父组件Expanded 包裹或使用 ListView
布局不对齐未设置对齐方式使用 Align / Center
列表只显示一项未给列表指定高度Expanded 包裹或给 shrinkWrap: true

下一步

基于 Flutter 官方文档整理