Flutter项目中,字体设置fontWeight,中英文显示差异问题

459 阅读4分钟

问题表现

  1. 安卓下的表现
image.png
  1. iphone下的表现
Simulator Screenshot - iPhone 15 - 2024-09-20 at 20.09.43.png
  1. 再看下实现的代码
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: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter 爬坑示例'),
        ),
        body: const Center(
          child: DefaultTextStyle(
            style: TextStyle(
              color: Colors.black,
              fontSize: 16.0,
              height: 2,
            ),
            child: Column(
              children: [
                Text(
                  'AaBbCcDd 我是中文 123456 -- w100',
                  style: TextStyle(fontWeight: FontWeight.w100),
                ),
                Text(
                  'AaBbCcDd 我是中文 123456 -- w200',
                  style: TextStyle(fontWeight: FontWeight.w200),
                ),
                Text(
                  'AaBbCcDd 我是中文 123456 -- w300',
                  style: TextStyle(fontWeight: FontWeight.w300),
                ),
                Text(
                  'AaBbCcDd 我是中文 123456 -- w400',
                  style: TextStyle(fontWeight: FontWeight.w400),
                ),
                Text(
                  'AaBbCcDd 我是中文 123456 -- w500',
                  style: TextStyle(fontWeight: FontWeight.w500),
                ),
                Text(
                  'AaBbCcDd 我是中文 123456 -- w600',
                  style: TextStyle(fontWeight: FontWeight.w600),
                ),
                Text(
                  'AaBbCcDd 我是中文 123456 -- w700',
                  style: TextStyle(fontWeight: FontWeight.w700),
                ),
                Text(
                  'AaBbCcDd 我是中文 123456 -- w800',
                  style: TextStyle(fontWeight: FontWeight.w800),
                ),
                Text(
                  'AaBbCcDd 我是中文 123456 -- w900',
                  style: TextStyle(fontWeight: FontWeight.w900),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}


以上的例子中,我对每个Text都设置了不同的fontWeight,但是表现却完全不是想要的结果:

  1. 在安卓手机上,英文和数字是符合预期的,但是中文就不符合,要w600及以上才能产生效果,w600以下基本没有任何加粗效果,约等于w100
  2. 在iphone上,英文和数字也是符合预期的,但是中文也是不符合,情况跟安卓还不一样,虽然也是要w600及以上才能起效果,但是w100-w500完全是一样的,而且跟normal一样,也就是约等于w400

于是上网搜索了一番,google,掘金等等,结果找到一个说法(github.com/CarGuo/gsy_… ),大致意思就是:

  1. 手机会根据配置的字体,如果没有配置,就用手机默认字体来渲染,但是由于手机对于中文的支持有限,或者对于fontWeight权重的支持有限,导致有些字体渲染不一致,例如中文,韩国文字等等
  2. 提供的解决方式就是通过配置 fontFamilyFallback,于是我修改代码如下
// 主要修改公共样式部分
TextStyle(
  color: Colors.black,
  fontSize: 16.0,
  height: 2,
  fontFamilyFallback: [
    "PingFang SC",
    "Heiti SC",
    "Roboto",
  ],
),

在 Flutter 中,fontFamilyFallback是用于指定字体回退列表的属性,其主要作用是在指定的主要字体无法找到或加载失败时,依次尝试使用回退列表中的字体,以确保文本能够以合适的字体显示。

修改完后,我很高兴,以为应该可以爬出坑了,但是高兴了一半。查看结果发现,iphone没有问题,但是安卓还是没有效果。如下图

  1. iphone效果图,中文显示如预期
Simulator Screenshot - iPhone 15 - 2024-09-20 at 20.34.24.png
  1. 再看看安卓的,中文显示还是和原来一样
image.png

又经过了一顿google,掘金等等查找,来自多方面的总结,

  1. 除了以上的分析,虽然添加了fontFamilyFallback,但是对于PingFang SC, Heiti SC,Roboto, 前面两个安卓系统不支持
  2. Roboto虽然安卓支持,但是对于fontWeight支持度不够

于是网上有找到方案,就是引入自定义字体,但是该用什么字体呢?有的说用NotoSans,Noto Sans 是谷歌(Google)与 Adobe 合作推出的一款无衬线字体。

但是经过我一番捣腾之后,发现NotoSans其实也是对于中文支持不够,效果还是没有符合预期

最后我在某个网站发现,其实还有另外一种字体NotoSansSC Noto Sans SC 是 Noto 字体系列中的一个分支,专门用于显示简体中文文字。“SC”是 “Simplified Chinese”的缩写,意指简化字。这款字体是为了确保在显示任何简体中文文本时,即使某些非常见或特殊的字符不在常见的字体支持范围内,也能够正确地显示出来。

于是我就开始测试该方法

  1. 先下载NotoSansSC,到谷歌网站 (fonts.google.com/noto/specim…
  2. 在flutter项目根目录创建个目录存放,一般是根目录下 assets/fonts/
  3. 然后找到根目录下的pubspec.yaml,添加一下代码
fonts:
- family: NotoSansSC  // 这个名字可以自己定义
  fonts:
    - asset: assets/fonts/NotoSansSC/NotoSansSC-Thin.ttf
      weight: 100
    - asset: assets/fonts/NotoSansSC/NotoSansSC-ExtraLight.ttf
      weight: 200
    - asset: assets/fonts/NotoSansSC/NotoSansSC-Light.ttf
      weight: 300
    - asset: assets/fonts/NotoSansSC/NotoSansSC-Regular.ttf
      weight: 400
    - asset: assets/fonts/NotoSansSC/NotoSansSC-Medium.ttf
      weight: 500
    - asset: assets/fonts/NotoSansSC/NotoSansSC-SemiBold.ttf
      weight: 600
    - asset: assets/fonts/NotoSansSC/NotoSansSC-Bold.ttf
      weight: 700
    - asset: assets/fonts/NotoSansSC/NotoSansSC-ExtraBold.ttf
      weight: 800
    - asset: assets/fonts/NotoSansSC/NotoSansSC-Black.ttf
      weight: 900
  1. 然后页面上就可以使用了
fontFamilyFallback: [
    'NotoSansSC',
    "PingFang SC", 
],
  1. 重启下程序,flutter run,查看结果,终于没有问题。
image.png

总结,其实该问题主要还是系统或者框架的支持不够,该方案还是不算最佳方案,需要引入外部字体,如果你们有更好,更方便的方案,请在文章后面评论说明,感谢!

还有,如果你们不喜欢NotoSansSC,其他字体也是可以的,只要能够支持中文渲染,就可以。