You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:如何根据组件尺寸实现差异化布局?

Flutter实现自适应文本行布局(蓝色背景)

核心思路

要实现这种自适应布局,关键是动态判断文本总宽度是否超出可用空间,然后切换两种布局逻辑:

  • 文本总宽度 ≤ 可用宽度:用Row展示所有文本
  • 文本总宽度 > 可用宽度:仅展示前两个文本,末尾添加省略号

具体通过LayoutBuilder获取父容器的可用宽度,结合TextPainter计算每个文本的实际渲染宽度,再做判断。

完整代码实现

import 'package:flutter/material.dart';

class AdaptiveTextRow extends StatelessWidget {
  final List<String> texts;
  final TextStyle textStyle;
  final Color backgroundColor;

  const AdaptiveTextRow({
    super.key,
    required this.texts,
    this.textStyle = const TextStyle(fontSize: 16),
    this.backgroundColor = Colors.blue,
  });

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        // 计算所有文本的总宽度
        double totalWidth = 0;
        texts.forEach((text) {
          final painter = TextPainter(
            text: TextSpan(text: text, style: textStyle),
            textDirection: TextDirection.ltr,
          )..layout(maxWidth: constraints.maxWidth);
          totalWidth += painter.width;
        });

        // 判断是否超出可用宽度
        final isOverflow = totalWidth > constraints.maxWidth;

        return Container(
          padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
          color: backgroundColor,
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              // 固定展示前两个文本
              Text(texts[0], style: textStyle),
              if (texts.length >= 2) Text(texts[1], style: textStyle),
              // 根据溢出状态切换后续内容
              if (isOverflow)
                const Text('...', style: TextStyle(fontSize: 16))
              else
                ...texts.skip(2).map((text) => Text(text, style: textStyle)),
            ],
          ),
        );
      },
    );
  }
}

// 使用示例
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('自适应文本行示例')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('文本较短时:'),
            const SizedBox(height: 8),
            AdaptiveTextRow(
              texts: ['Text1', 'Text2', 'Text3'],
            ),
            const SizedBox(height: 20),
            const Text('文本较长时:'),
            const SizedBox(height: 8),
            AdaptiveTextRow(
              texts: [
                'Text1这是很长的文本内容',
                'Text2这也是一段超长文本',
                'Text3还有更多要展示的内容',
                'Text4最后一段文本'
              ],
            ),
          ],
        ),
      ),
    );
  }
}

关键细节说明

  1. LayoutBuilder的作用:获取父容器的constraints.maxWidth,也就是当前Widget能使用的最大宽度,以此作为判断是否溢出的依据。
  2. TextPainter计算宽度:因为每个文本的内容、样式不同,实际渲染宽度也不一样,通过TextPainter.layout()可以精准计算每个文本的实际宽度,求和后和可用宽度对比。
  3. 动态布局切换:根据isOverflow变量,决定是展示全部文本还是仅前两个加省略号,Row的mainAxisSize: MainAxisSize.min确保Widget只占用必要宽度,避免多余留白。

内容的提问来源于stack exchange,提问作者ximmyxiao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 07:05:31