Flutter Web应用iOS端Google NotoSans字体显示异常如何修复
问题说明
- 开发场景:基于Flutter 3.0.2开发Flutter Web应用,使用NotoSans字体同时展示英文、天城文(印地语)内容,MacOS系统Chrome浏览器下显示完全正常
- 异常表现:iOS设备(iPhone 11)上文本渲染错乱,异常效果如下:

现有配置
pubspec.yaml 相关片段
# 构建时会打包进应用的依赖 dependencies: flutter: sdk: flutter # 多语言支持 flutter_localizations: sdk: flutter intl: ^0.17.0 # 字体与图标资源 google_fonts: ^3.0.1 # 构建时不会打包进应用的开发依赖 dev_dependencies: flutter_test: sdk: flutter # 代码格式化规范 flutter_lints: ^2.0.1 # Flutter相关配置 flutter: uses-material-design: true # 国际化配置 generate: true # 静态资源目录 assets: - assets/images/ - assets/images/brands/ - assets/images/flags/ - assets/icons/ - assets/videos/ - assets/fonts/ # 自定义字体配置 fonts: - family: NotoSans fonts: - asset: assets/fonts/NotoSansRegular.ttf - asset: assets/fonts/NotoSansBold.ttf weight: 700 - asset: assets/fonts/NotoSansItalic.ttf style: italic
theme.dart 文本主题相关片段
class StrawmerryTheme { ThemeData get theme => ThemeData( textTheme: TextTheme( titleSmall: const TextStyle( fontFamily: 'NotoSans', fontSize: 34, fontWeight: FontWeight.bold, letterSpacing: 0.25, color: Colors.black), // 页面标题 headlineLarge: TextStyle( fontFamily: 'NotoSans', fontSize: 34, fontWeight: FontWeight.bold, letterSpacing: 0.25, color: Colors.grey.shade800, ), // 页面板块标题 headlineMedium: TextStyle( fontFamily: 'NotoSans', fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: -1, color: Colors.grey.shade800, ), headlineSmall: TextStyle( fontFamily: 'NotoSans', fontSize: 20, fontWeight: FontWeight.bold, letterSpacing: 0.15, color: Colors.grey.shade800, ), // 正文文本 bodyMedium: TextStyle( fontFamily: 'NotoSans', fontSize: 16, fontWeight: FontWeight.normal, letterSpacing: 0.5, color: Colors.grey.shade800, ), // 单位文本 bodySmall: TextStyle( fontFamily: 'NotoSans', fontSize: 12, fontWeight: FontWeight.normal, letterSpacing: 0.4, color: Colors.grey.shade800, ), // 按钮文本 labelMedium: const TextStyle( fontFamily: 'NotoSans', fontSize: 22, fontWeight: FontWeight.normal, letterSpacing: 1.0, color: Colors.white, ), ), ), }
问题根因
你本地存放的三个NotoSans字体文件是仅覆盖拉丁(英文)字符集的子集版本,没有包含天城文(印地语)对应的字形数据。Mac端Chrome显示正常是因为桌面端浏览器自带完善的字体回退机制,遇到当前字体缺失的字符会自动调用系统内置的对应脚本字体补全渲染;但iOS端Web内核对跨字体的字形回退支持存在限制,找不到对应字形时就会出现字符错位、重叠、渲染破碎的问题,和你动图里的异常表现完全一致。
修复方案
三选一即可,优先推荐前两种:
- 替换全量字体包:下载包含天城文字符集的完整NotoSans字体文件,替换
assets/fonts目录下现有的三个ttf文件,注意不要选择仅支持Latin(拉丁)的子集版本,要选标注支持Devanagari(天城文)的版本,替换后重新构建即可。 - 直接使用google_fonts包的能力:你已经引入了
google_fonts依赖,不需要在本地存放字体文件,也不用在pubspec.yaml中声明fonts字段,直接通过包提供的方法生成文本主题即可,包会自动根据页面渲染的字符拉取对应语言的字体子集,不会出现缺字问题。示例配置如下:ThemeData get theme => ThemeData( textTheme: GoogleFonts.notoSansTextTheme( TextTheme( // 保留你原来所有的字号、字重、颜色、字间距配置即可,不需要手动指定fontFamily titleSmall: const TextStyle( fontSize: 34, fontWeight: FontWeight.bold, letterSpacing: 0.25, color: Colors.black), // 其余TextStyle配置和原有逻辑完全一致 ) ), ); - 显式配置字体回退链:如果不想替换现有本地字体,可以额外引入NotoSans天城文字体文件到pubspec的fonts配置中,然后在所有TextStyle里添加
fontFamilyFallback参数,指定找不到字符时的备用字体:TextStyle( fontFamily: 'NotoSans', // 其余原有配置不变 fontFamilyFallback: ['NotoSansDevanagari', 'sans-serif'], )
注意:修改字体配置后必须执行
flutter clean清除构建缓存,再重新启动编译,否则旧的缓存字体资源会导致修改不生效。
内容的提问来源于stack exchange,提问作者Martin Reindl
相关产品推荐
相关产品推荐

