是什么
LayoutBuilder 是一个 Flutter 的 布局小部件,它可以让你在 构建子组件时,获取父组件的约束(BoxConstraints),从而根据不同的空间大小构建出不同的布局。
通俗地说:
- 一般的 widget:在 build 阶段就确定子 widget。
- LayoutBuilder:等到布局(layout)时,父容器把约束条件(最大/最小宽高)传过来,再根据这些约束决定如何构建子 widget。
所以它特别适合 响应式布局 场景,比如:
- 小屏幕用一列显示,大屏幕用两列显示。
- 父容器空间不够时缩小或替换 widget。
构造函数
// 继承自 ConstrainedLayoutBuilder<BoxConstraints>
// 泛型参数固定为 BoxConstraints(也就是盒模型约束)
//createRenderObject 返回 _RenderLayoutBuilder,它是一个 RenderObject,负责在 布局阶段触发 builder。
class LayoutBuilder extends ConstrainedLayoutBuilder<BoxConstraints> {
/// Creates a widget that defers its building until layout.
const LayoutBuilder({super.key, required super.builder});
@override
RenderAbstractLayoutBuilderMixin<BoxConstraints, RenderBox> createRenderObject(
BuildContext context,
) => _RenderLayoutBuilder();
}
// 是一个抽象类,接收一个泛型 ConstraintType,必须是 Constraints 的子类。
// 对 LayoutBuilder 来说,就是 BoxConstraints。
// 核心参数 Widget Function(BuildContext context, ConstraintType constraints) builder;
// 这个 builder 就是用户写的回调函数,真正决定 UI 如何渲染。
// builder 的返回值类型是 Widget,可以返回任何 widget(甚至是一个 Scaffold)。
abstract class ConstrainedLayoutBuilder<ConstraintType extends Constraints>
extends AbstractLayoutBuilder<ConstraintType> {
/// Creates a widget that defers its building until layout.
const ConstrainedLayoutBuilder({super.key, required this.builder});
@override
final Widget Function(BuildContext context, ConstraintType constraints) builder;
}
应用一:响应式布局
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'LayoutBuilder Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const ResponsivePage(),
);
}
}
class ResponsivePage extends StatelessWidget {
const ResponsivePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("LayoutBuilder 示例")),
body: LayoutBuilder(
builder: (context, constraints) {
// 根据父容器的宽度决定布局
if (constraints.maxWidth < 600) {
// 小屏幕:用 Column(竖排)
return Column(
children: [
Expanded(
child: Container(
color: Colors.red,
child: const Center(child: Text("Item 1")),
),
),
Expanded(
child: Container(
color: Colors.green,
child: const Center(child: Text("Item 2")),
),
),
],
);
} else {
// 大屏幕:用 Row(横排)
return Row(
children: [
Expanded(
child: Container(
color: Colors.red,
child: const Center(child: Text("Item 1")),
),
),
Expanded(
child: Container(
color: Colors.green,
child: const Center(child: Text("Item 2")),
),
),
],
);
}
},
),
);
}
}
应用二:字体大小随父容器宽度变化
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'LayoutBuilder Font Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const FontResponsivePage(),
);
}
}
class FontResponsivePage extends StatelessWidget {
const FontResponsivePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("LayoutBuilder 自适应字体示例")),
body: Center(
child: LayoutBuilder(
builder: (context, constraints) {
// 根据父容器的宽度决定字体大小
double fontSize = constraints.maxWidth / 15;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"屏幕宽度: ${constraints.maxWidth.toStringAsFixed(2)}",
style: TextStyle(fontSize: 30),
),
Text(
"字体大小: ${fontSize.toStringAsFixed(2)}",
style: TextStyle(fontSize: 30),
),
Container(
color: Colors.amber[200],
width: constraints.maxWidth * 0.8,
height: 200,
alignment: Alignment.center,
child: Text(
"自适应字体",
style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
),
),
),
],
);
},
),
),
);
}
}
应用三:根据容器大小显示不同颜色
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'LayoutBuilder Container Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const ColorResponsivePage(),
);
}
}
class ColorResponsivePage extends StatelessWidget {
const ColorResponsivePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("LayoutBuilder 颜色示例")),
body: Center(
child: Container(
width: 100, // 可以尝试改小,比如 150
height: 200,
alignment: Alignment.center,
child: LayoutBuilder(
builder: (context, constraints) {
// 根据父容器宽度决定颜色
Color color;
if (constraints.maxWidth < 200) {
color = Colors.red;
} else if (constraints.maxWidth < 400) {
color = Colors.green;
} else {
color = Colors.blue;
}
return Container(
width: constraints.maxWidth,
height: constraints.maxHeight,
color: color,
child: Center(
child: Text(
"宽度: ${constraints.maxWidth.toStringAsFixed(0)}",
style: const TextStyle(color: Colors.white, fontSize: 20),
),
),
);
},
),
),
),
);
}
}