Flutter:如何更改默认字体

我的项目目前在 Windows 上运行并显示注册页面。这个页面本身有点过时了。最近的趋势是先显示 OAuth 供应商的按钮,因为大多数用户更喜欢它们。

但是,对于这篇文章来说,这样没问题。

因为它运行在 Windows 上,所以默认字体是 SegoeUI。在 Android 和 Web 上默认是 Roboto,在 iOS 上默认是 SF Pro。

我们为什么要更改它?实际上我们不必更改。

但我的理由是:

  • 在所有平台上使用相同的字体。
  • 不使用默认字体,因为使用默认字体的应用程序看起来很"默认"。
  • 我查看了 Google Fonts 并选择了 Open Sans。

它比 Roboto 更透气、更轻盈一些,是继 Roboto 之后第二受欢迎的 Google 字体。但由于 Roboto 是 Android 上的默认字体(并被 Google 广泛使用),我们可以假设 Open Sans 在没有 Google 影响的情况下会是最受欢迎的。

它也比 Apple 专有的 SF Pro 更轻盈、更透气:

那么,如何用 Open Sans 替换默认字体呢?

我所知道的:

  • 下载字体并解压。

有两种 可变字体(Variable Fonts):常规 (regular)和斜体 (italic)。可变 意味着它的宽度字重 (weight)可以被代码动态地改变:

dart 复制代码
TextStyle(  
fontFamily: 'OpenSans',  
fontVariations: [  
FontVariation('wdth', 77),  
FontVariation('wght', 477),  
]);

还有一个 static 文件夹,里面是静态字体。可变字体文件是 500 KB,而静态字体只有 130 KB。如果你最终只使用一个变体,例如 Open Sans Medium,你可以节省一些空间。不过,我不会为此费心。

    1. 将其放入 assets 文件夹。

我拿了一个常规可变字体并重新命名了它。

剩下的字体是用于实验的;我不打算在同一个应用中使用所有这些字体。😎

    1. pubspec.yaml 中指定字体。
yaml 复制代码
flutter:
  uses-material-design: true
  assets: 
    - assets/images/
    - assets/images/background/
    - assets/audio/
  fonts:
    - family: OpenSans
      fonts: 
        - asset: assets/fonts/OpenSans.ttf

我知道如何用 TextStyleText 组件设置 fontFamily。但我想全局设置它。

原来,这可以通过** ThemeData **来实现,真是个惊喜:

dart 复制代码
 static ThemeData getTheme(
    ColorScheme colorScheme,
    Brightness brightness,
  ) {
    return ThemeData(
      brightness: brightness,
      colorScheme: colorScheme,
      fontFamily: 'OpenSans',    //<-here
      appBarTheme: AppBarTheme(
...

上面是我的方法,它为应用创建了 ThemeData 对象。修复很简单------只需添加 fontFamily 属性。但如果这么简单,我就不会写这篇文章了。

如你所见(你可能看不到 😀),只有 TextTextFields 组件中的字体发生了变化。(提示:看看字母 g)。但 AppBar 标题和按钮仍然使用默认字体。

首先,我得说这很令人失望。如果这种设置整个 ThemeData 字体的方式对整个 ThemeData 不起作用,那设置它的意义何在?

或许我做错了什么?可能吧,因为我是第一次做。请帮忙。

好吧,我咨询了 Claude,这位又大又漂亮的 LLM 建议:

dart 复制代码
textTheme: Typography.englishLike2021
          .copyWith(
            bodyMedium: const TextStyle(fontSize: 16),
            bodySmall: const TextStyle(fontSize: 15),
            headlineMedium: TextStyle(color: colorScheme.primary),
            labelLarge: const TextStyle(fontSize: 15),
            labelMedium: const TextStyle(fontSize: 14),
            bodyLarge: TextStyle(
              fontSize: 17,
              color: colorScheme.onSurface,
            ),
          )
          .apply(  //<-this
            fontFamily: 'OpenSans',
          ),

添加 apply(fontFamily: 'OpenSans',)textTheme 中。没用。按钮和 AppBar 仍然使用默认字体。这个方法实际上是有效的;它可以用来替代设置 ThemeDatafontFamily 属性。但它的作用方式是同样的局限。

下一个建议(这次奏效了)是分别在 AppBarTheme 和每个按钮的主题中指定 fontFamily

dart 复制代码
 appBarTheme: AppBarTheme(
        foregroundColor: colorScheme.primary,
        elevation: 0,
        scrolledUnderElevation: 2,
        centerTitle: true,
        titleTextStyle: TextStyle(
          fontSize: 17,
          fontWeight: FontWeight.w600,
          color: colorScheme.onSurface,
          fontFamily: 'OpenSans',   //<-here
        ),
      ),

我使用了所有的 Material 按钮(Elevated、Filled、Outlined 和 Text),所以我需要为它们每一个修改以下内容:

dart 复制代码
 textStyle: WidgetStateProperty.resolveWith<TextStyle?>(
        (states) {
          if (states.contains(WidgetState.hovered)) {
            return TextStyle(
              fontSize: 16,
             // fontWeight: FontWeight.w800,
              fontFamily: 'OpenSans',  //<-here
              fontVariations: [
                      FontVariation('wght', 800),
                    ]
            );
          }
          return TextStyle(
            fontSize: 17,
           // fontWeight: FontWeight.w600,
            fontFamily: 'OpenSans',    //<-and here
            fontVariations: [
                      FontVariation('wght', 600),
                    ]
          );
        },
      ),

fontWeight 属性不适用于 Open Sans;我们应该改用 fontVariations

然后瞧(终于 😴),Open Sans 无处不在:

我已经觉得这篇文章值得写了,但无论如何......

奖励 1

让文本字段的标签使用等宽字体(monospace)。

奖励 2

对标题使用另一种(更有趣的)字体。

将字体添加到 assets

(这两种字体都是和 Open Sans 一起从 Google Fonts 下载的)。

顺便说一下,VS Code 有一个非常有用的扩展叫 Font Preview

  1. 将字体添加到 pubspec.yaml
yaml 复制代码
flutter:
  uses-material-design: true
  assets: 
    - assets/images/
    - assets/images/background/
    - assets/audio/
  fonts:
    - family: OpenSans
      fonts: 
        - asset: assets/fonts/OpenSans.ttf
    - family: KodeMono
      fonts: 
        - asset: assets/fonts/KodeMono.ttf
    - family: StardosStencil
      fonts: 
        - asset: assets/fonts/StardosStencil.ttf  
  1. 最后,修改 textTheme
dart 复制代码
 textTheme: Typography.englishLike2021
          .copyWith(
            bodyMedium: const TextStyle(fontSize: 15),
            bodySmall: const TextStyle(fontSize: 14),
            headlineMedium: TextStyle(
              color: colorScheme.primary,
              fontFamily: 'StardosStencil',   //<-here
              fontSize: 25,
            ),
            labelLarge: const TextStyle(fontSize: 15),
            labelMedium: const TextStyle(fontSize: 14),
            bodyLarge: TextStyle(
              fontSize: 16,
              color: colorScheme.onSurface,
              fontFamily: 'KodeMono',        //<-and here
            ),
          )
          // .apply(
          //   fontFamily: 'OpenSans',
          // )
          ,

👉(别忘了移除 apply 方法,它会覆盖所有指定的字体。)

这是我的注册页面,有一个有趣的标题和等宽的文本字段标签:

顺便说一句,我的显示"Create Account"文本的 Text 组件看起来像:

dart 复制代码
       Text(
            'Create Accountg',
            style: Get.textTheme.headlineMedium,                       
          ),

所以,我们明确地使用了 textTheme 中的 headlineMedium 样式。

关于文本字段标签,情况有所不同:

dart 复制代码
TextField(
            controller: _emailController,
            decoration: InputDecoration(
              labelText: 'Emailg',
              prefixIcon: Icon(
                Icons.email_outlined,
              ),
            ),
          ),

正如我们所见,labelStyle 没有定义。TextField 隐式地使用 textTheme 中的 bodyLarge TextStyle 对象作为其标签。

我一直以为 GetX 会在内部的某个地方缓存 ThemeData,并且所有的 Get.themeGet.textTheme 之类的调用都不会以 Theme.of(context) 查找结束。运气不好。

这是 GetX 内部的 theme getter 实现:

dart 复制代码
 ThemeData get theme {
    var theme = ThemeData.fallback();
    if (context != null) {
      theme = Theme.of(context!);
    }
    return theme;
  }

只是要意识到(如果您使用 GetX)。

那些 .of(context) 查找可能会对性能造成负担,最好在 build 方法的顶部缓存 ThemeData 对象。

就是这样。

感谢您的阅读。

如果您学到了新东西,您就欠我鼓掌。开玩笑 😀。半开玩笑 😉。

相关推荐
默海笑9 分钟前
VUE后台管理系统:定制化、高可用前台样式处理方案
前端·javascript·vue.js
YaeZed16 分钟前
Vue3-toRef、toRefs、toRaw
前端·vue.js
用户66006766853917 分钟前
CSS定位全解析:从static到sticky,彻底搞懂布局核心
前端·css
听风说图17 分钟前
Figma Vector Networks: 形状、填充及描边
前端
hanliu200321 分钟前
实训11 ,百度评分
前端
Y***K43426 分钟前
TypeScript模块解析
前端·javascript·typescript
JarvanMo29 分钟前
Xcode 没人想解决的问题:为什么苹果对平庸感到满意
前端
合作小小程序员小小店43 分钟前
web网页开发,在线%餐饮点餐%系统,基于Idea,html,css,jQuery,java,ssm,mysql。
java·前端·数据库·html·intellij-idea·springboot
鹏多多1 小时前
HTML的Video从基础使用到高级实战+兼容的完全指南
前端·javascript·vue.js