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

能否获取被FittedBox调整后的Text组件字号并同步给其他Text组件

解决方案

你最初的思路不生效的核心原因是:FittedBox 对文本的缩放是通过绘制时施加变换矩阵实现的,并不会修改子Text组件本身的style.fontSize属性,你直接从Widget结构里读取的永远是最初设置的原始字号,不是缩放后的实际显示字号。

推荐实现方案(无二次渲染,性能最优)

我们可以通过TextPainter模拟FittedBox的缩放逻辑,提前计算出长文本适配容器后的实际字号,直接给所有需要同步的Text组件使用即可,不需要依赖组件渲染后再取值更新。

  • 第一步:先实现字号计算工具函数
double calculateAdaptedFontSize({
  required String text,
  required TextStyle style,
  required double maxWidth,
  required double maxHeight,
  double minFontSize = 1,
  double maxFontSize = 100,
}) {
  double fontSize = maxFontSize;
  late TextPainter painter;
  while (fontSize >= minFontSize) {
    painter = TextPainter(
      text: TextSpan(text: text, style: style.copyWith(fontSize: fontSize)),
      maxLines: 1,
      textDirection: TextDirection.ltr,
    );
    painter.layout(maxWidth: double.infinity);
    if (painter.width <= maxWidth && painter.height <= maxHeight) {
      break;
    }
    fontSize -= 1;
  }
  return fontSize;
}
  • 第二步:结合你的布局实现字号同步
class Bar extends StatefulWidget {
  const Bar({super.key});

  @override
  State<Bar> createState() => _Foo();
}

class _Foo extends State<Bar> {
  // 作为基准的长文本
  final String baseText = 'Much Longer';
  // 文本通用基础样式
  final TextStyle baseStyle = const TextStyle(color: Colors.black);

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        // 计算基准文本所在容器的宽高(根据你的布局结构得出)
        // 外层Column两个Expanded平分高度
        final maxHeight = constraints.maxHeight / 2;
        // 内层Row两个Expanded平分宽度
        final maxWidth = constraints.maxWidth / 2;

        // 计算适配后的统一字号
        final adaptedFontSize = calculateAdaptedFontSize(
          text: baseText,
          style: baseStyle,
          maxWidth: maxWidth,
          maxHeight: maxHeight,
        );

        return Column(
          children: [
            Expanded(
              child: Row(
                children: [
                  Expanded(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        // 短文本直接使用计算出的统一字号
                        Text(
                          'Short',
                          style: baseStyle.copyWith(fontSize: adaptedFontSize),
                        ),
                      ],
                    ),
                  ),
                  const Expanded(child: SizedBox()),
                ],
              ),
            ),
            Expanded(
              child: Row(
                children: [
                  const Expanded(child: SizedBox()),
                  Expanded(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        // 长文本也使用计算出的字号,无需再套FittedBox
                        Text(
                          baseText,
                          style: baseStyle.copyWith(fontSize: adaptedFontSize),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ],
        );
      },
    );
  }
}

备选方案(从渲染完成的FittedBox取实际字号)

如果你一定要保留FittedBox包裹基准Text的逻辑,可以通过GlobalKey获取渲染后的变换参数计算实际字号,该方案会触发一次额外重绘,首次加载会有短暂的字号跳动:

class _Foo extends State<Bar> {
  final GlobalKey _fittedBoxKey = GlobalKey();
  double? _adaptedFontSize;
  // 基准Text原始字号设足够大,保证会被FittedBox缩放
  final double _originalFontSize = 100;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // 组件渲染完成后读取缩放比例
      final renderBox = _fittedBoxKey.currentContext?.findRenderObject() as RenderBox?;
      if (renderBox == null) return;
      final transform = renderBox.getTransformTo(null);
      final scale = transform.getMaxScaleOnAxis();
      // 计算实际字号并更新
      setState(() {
        _adaptedFontSize = _originalFontSize * scale;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: Row(
            children: [
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text(
                      'Short',
                      style: TextStyle(fontSize: _adaptedFontSize ?? 14),
                    ),
                  ],
                ),
              ),
              const Expanded(child: SizedBox()),
            ],
          ),
        ),
        Expanded(
          child: Row(
            children: [
              const Expanded(child: SizedBox()),
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    FittedBox(
                      key: _fittedBoxKey,
                      fit: BoxFit.fill,
                      child: Text(
                        'Much Longer',
                        style: TextStyle(fontSize: _originalFontSize),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 04:15:01