布局组件:LayoutBuilder

  1. 是什么
  2. 构造函数
  3. 应用一:响应式布局
  4. 应用二:字体大小随父容器宽度变化
  5. 应用三:根据容器大小显示不同颜色

是什么

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),
                  ),
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

×

喜欢就点赞,疼爱就打赏