4、文字主题定制:TextTheme 详解,定义标题、正文、按钮等各级文字样式。

好,咱们进入主题定制的核心环节——文字。你想想看,一个App好不好看,一半的功劳得给字体和排版。Flutter 里管这个叫 TextTheme,说白了就是一套「文字样式模板」。你只要定义好这套模板,全App的标题、正文、按钮文字就都统一了。

我个人习惯,在项目一开始就把 TextTheme 定死。为什么?因为后期改字体大小、颜色,那真是牵一发动全身,改到想哭。我早期一个项目就吃过这个亏,当时没统一管理,结果设计师说「标题再大2像素吧」,我改了十几个页面……嗯,从那以后,我再也不敢偷懒了。

4.1 TextTheme 的结构:它到底包含哪些样式?

Flutter 的 TextTheme 其实是一个「样式集合」。它把文字分成了几个层级,从最大的标题到最小的说明文字。咱们先看一张表,你就明白了:

属性名 用途 默认大小(Material 3)
displayLarge 超大标题,比如欢迎页、数字展示 57px
displayMedium 次大标题 45px
displaySmall 稍小的大标题 36px
headlineLarge 页面主标题,比如文章标题 32px
headlineMedium 区块标题 28px
headlineSmall 卡片标题 24px
titleLarge 列表项标题、对话框标题 22px
titleMedium 列表项副标题 16px
titleSmall 小标题,比如按钮文字 14px
bodyLarge 正文,默认字体 16px
bodyMedium 次要正文 14px
bodySmall 辅助文字、说明 12px
labelLarge 按钮、标签 14px
labelMedium 小标签、chip 12px
labelSmall 极小文字,比如角标 11px
我的小技巧: 你不需要全部定义。我一般只定义 headlineLargetitleLargebodyLargelabelLarge 这四个,其他用默认值。够用,还省事。

4.2 如何自定义 TextTheme?

直接上代码。你需要在 ThemeData 里传入一个 TextTheme 对象。看这个例子:

ThemeData(
  textTheme: TextTheme(
    // 页面主标题:加粗,深色
    headlineLarge: TextStyle(
      fontSize: 28,
      fontWeight: FontWeight.bold,
      color: Colors.black87,
    ),
    // 卡片标题:中等粗细
    titleLarge: TextStyle(
      fontSize: 20,
      fontWeight: FontWeight.w600,
      color: Colors.black87,
    ),
    // 正文:常规大小,灰色
    bodyLarge: TextStyle(
      fontSize: 16,
      fontWeight: FontWeight.normal,
      color: Colors.black54,
    ),
    // 按钮文字:全大写,加粗
    labelLarge: TextStyle(
      fontSize: 14,
      fontWeight: FontWeight.bold,
      letterSpacing: 1.2,
      color: Colors.white,
    ),
  ),
)

你看,这样定义之后,你在任何地方用 Text('标题', style: Theme.of(context).textTheme.headlineLarge),它都会自动应用这个样式。是不是很爽?

重点: 记得在 TextStyle 里只写 通用属性。比如颜色、大小、字重。不要写背景色、边框这些,那些应该用 ContainerButtonStyle 去控制。

4.3 避坑指南:我踩过的三个坑

讲几个实战中容易翻车的地方。我曾经……嗯,都经历过。

  • 坑一:字体大小写不一致。 我早期定义 labelLarge 时忘了加 letterSpacing,结果按钮文字挤在一起,设计师说「不够大气」。后来我统一给按钮加了 letterSpacing: 1.0,效果立竿见影。
  • 坑二:颜色写死。 如果你在 TextTheme 里直接写 Colors.black,那暗黑模式就废了。我建议用 Theme.of(context).colorScheme.onSurface 这种动态颜色。这样亮暗模式自动切换。
  • 坑三:忘了适配不同平台。 在 iOS 上,系统默认字体是 San Francisco,Android 是 Roboto。如果你自定义字体,记得在 TextStyle 里指定 fontFamily,或者用 GoogleFonts 包。不然跨平台效果不一样。
警告: 不要直接修改 ThemeDatatextTheme 默认对象。比如 ThemeData().textTheme.headlineLarge 这样取出来再改,可能会影响其他组件。一定要新建一个 TextTheme 实例传进去。

4.4 实战:给按钮文字加点「个性」

按钮文字通常用 labelLarge。但有时候你需要按钮文字有不同颜色(比如禁用状态)。这时候怎么办?

我的做法是:在 TextTheme 里只定义基础样式,然后在 ButtonStyle 里覆盖颜色。看代码:

ThemeData(
  textTheme: TextTheme(
    labelLarge: TextStyle(
      fontSize: 14,
      fontWeight: FontWeight.w600,
      letterSpacing: 1.0,
      // 这里不写颜色
    ),
  ),
  elevatedButtonTheme: ElevatedButtonThemeData(
    style: ButtonStyle(
      textStyle: WidgetStatePropertyAll(
        Theme.of(context).textTheme.labelLarge?.copyWith(
          color: Colors.white, // 按钮文字颜色在这里控制
        ),
      ),
    ),
  ),
)

这样,按钮文字的大小、字重由 TextTheme 统一管理,颜色由 ButtonStyle 单独控制。职责清晰,后期改起来也方便。

4.5 总结一下

文字主题定制,说白了就是「先分层,再定义」。你想想看,一个App里文字层级就那么几种:标题、正文、按钮、说明。你只要把这几个层级的样式定好,全App就统一了。

我个人建议,每个项目都建一个 app_text_theme.dart 文件,专门放 TextTheme 的定义。这样以后换字体、改大小,只需要改这一个文件。我现在的项目就是这么干的,设计师改需求时,我改一行代码就行,省心得很。

下一节,咱们聊聊颜色主题。颜色比文字更复杂,因为还有亮暗模式、色盲适配这些坑。到时候我把我踩过的坑都抖出来,你注意避让。