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

Flutter应用中如何在所有文本旁展示对应Font Size与Weight用于测试

Flutter 全应用文本字号字重调试展示方案

以下两种方案均仅在调试模式下生效,不会侵入生产环境代码。

方案1:全局无侵入拦截(无需修改现有业务代码)

利用MaterialApp/CupertinoApp的builder参数全局拦截Widget树,自动识别所有Text组件并附加字号字重信息,支持覆盖第三方库内的文本。

实现代码

import 'package:flutter/foundation.dart';
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: '业务应用',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const HomePage(),
      // 全局拦截入口
      builder: (context, child) {
        // 仅调试模式开启
        if (!kDebugMode) return child!;
        return _DebugTextWrapper(child: child!);
      },
    );
  }
}

class _DebugTextWrapper extends StatelessWidget {
  final Widget child;
  const _DebugTextWrapper({required this.child});

  @override
  Widget build(BuildContext context) => _traverseWidgetTree(child);

  Widget _traverseWidgetTree(Widget widget) {
    // 识别Text组件,附加信息
    if (widget is Text) {
      final defaultStyle = DefaultTextStyle.of(context).style;
      final targetStyle = widget.style ?? defaultStyle;
      final fontSize = targetStyle.fontSize?.toStringAsFixed(1) ?? 'default';
      final fontWeight = targetStyle.fontWeight?.toString().split('.').last ?? 'default';
      // 两种展示方式二选一:
      // 方式1:Tooltip不破坏原有布局,PC端hover、移动端长按查看
      return Tooltip(
        message: '字号: $fontSize | 字重: $fontWeight',
        triggerMode: TooltipTriggerMode.longPress,
        child: widget,
      );
      // 方式2:直接在文本下方标注,直观展示但会影响原有布局
      // return Column(
      //   mainAxisSize: MainAxisSize.min,
      //   crossAxisAlignment: CrossAxisAlignment.start,
      //   children: [
      //     widget,
      //     Text(
      //       '[$fontSize | $fontWeight]',
      //       style: const TextStyle(fontSize: 8, color: Colors.redAccent),
      //     )
      //   ],
      // );
    }
    // 递归处理多子组件容器
    if (widget is MultiChildRenderObjectWidget) {
      return (widget.runtimeType as dynamic)(
        key: widget.key,
        children: widget.children.map(_traverseWidgetTree).toList(),
      ) as Widget;
    }
    // 递归处理单子组件容器
    if (widget is SingleChildRenderObjectWidget) {
      return (widget.runtimeType as dynamic)(
        key: widget.key,
        child: widget.child == null ? null : _traverseWidgetTree(widget.child!),
      ) as Widget;
    }
    // 其他组件直接返回
    return widget;
  }
}

方案优势

  • 零业务代码侵入,引入后直接生效
  • 覆盖范围完整,包括第三方依赖库内的Text组件

方案2:自定义全局Text组件(灵活控制展示粒度)

如果团队已统一使用封装的全局Text组件,直接在组件内添加调试逻辑即可,性能更优。

实现代码

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

class CustomText extends StatelessWidget {
  final String text;
  final TextStyle? style;
  // 其余Text的属性按需透传

  const CustomText(this.text, {super.key, this.style});

  @override
  Widget build(BuildContext context) {
    if (!kDebugMode) {
      return Text(text, style: style);
    }
    final defaultStyle = DefaultTextStyle.of(context).style;
    final targetStyle = style ?? defaultStyle;
    final fontSize = targetStyle.fontSize?.toStringAsFixed(1) ?? 'default';
    final fontWeight = targetStyle.fontWeight?.toString().split('.').last ?? 'default';
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(text, style: style),
        Text(
          '[$fontSize | $fontWeight]',
          style: const TextStyle(fontSize: 8, color: Colors.redAccent),
        )
      ],
    );
  }
}

方案优势

  • 性能更高,无需递归遍历整棵Widget树
  • 控制粒度灵活,可针对特定页面、特定文本单独开关展示逻辑

注意事项

  • 若选择直接标注的展示方式,建议测试完成后切换回Tooltip模式,避免影响UI还原度验证
  • 两种方案的调试逻辑在生产打包时会被自动摇树优化,不会增加生产包体积

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 14:36:04