win11 桌面开发 flutter3.x 中文字体和对齐问题

环境描述

  • 操作系统: win11
  • flutter版本相关版本
java 复制代码
Flutter 3.13.9 • channel stable • https://github.com/flutter/flutter.git
Framework • revision d211f42860 (8 days ago) • 2023-10-25 13:42:25 -0700
Engine • revision 0545f8705d
Tools • Dart 3.1.5 • DevTools 2.25.0

问题描述

默认情况下,flutter的中文字体会显示成这样

github 上相关 issue [Desktop-Windows]Chinese characters are incorrectly rendered in flutter 3 · Issue #103811 · flutter/flutter · GitHub

问题可能的原因

  • 可能是使用了日文字体
  • 为什么会使用日文字体? 可能是因为默认locale不正确

都只是可能,确切的原因不知道

如何解决?

无效的解决方式 : 通过配置locale解决

可能在2.x有效,但在我的环境下是无效的

有效解决方式

使用自定义中文字体。如: 鸿蒙字体小米字体OPPO Sans思源黑体

配置和使用自定义字体

pubspec.yaml

yaml 复制代码
fonts:
    - family: MiSans
      fonts:
        - asset: assets/fonts/MiSans-Regular.ttf
dart 复制代码
import 'dart:io';

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

void main() {
  debugPrint(Platform.localeName);
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      localizationsDelegates: const [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: const [
        Locale('zh', 'CN'), // 中文简体
        Locale('en', 'US'), // 美国英语
      ],
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
        // 默认字体: 这里使用的是 pubspec.yaml 文件中,自定义的字体
        fontFamily: 'MiSans',
        // 当默认字体中不包含对应文字时,会按顺序使用fallback中的字体渲染
        fontFamilyFallback: const [
          'MiSans',
          'Helvetica Neue',
          'PingFang SC',
          'Source Han Sans SC',
          'Noto Sans CJK SC'
        ],
      ),
      home: const MyHomePage(title: 'Flutter 中文测试'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(
          widget.title,
          style: const TextStyle(height: 1.5, fontSize: 18),
          locale: const Locale.fromSubtags(
              languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'Flutter 中文测试 如下是你点击按钮的次数:',
            ),
            const Text(
              '雷电将军',
            ),
            TextButton(
                onPressed: () => debugPrint('123'), child: const Text('角色按钮')),
            ElevatedButton(
                onPressed: () => debugPrint('123'), child: const Text('甘雨')),
            const Text('固件升级123'),
            const Text(
              'abc经营统计123!。;.;',
              style: TextStyle(fontWeight: FontWeight.bold),
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

效果对比

左边是配置自定义字体之后的效果,右边是未配置自定义字体的效果

可以看出右边的中文存在如下问题:

  • 即使是中文也无法完全对齐. 如:这个字,这个字
  • 英文,数字和数字同时出现时,无法对齐。如: abc经营统计123右边的是没有底线对齐的

字重(fontWeight)问题

按照上面的字体配置,让我们看看下面的效果图

abc经营统计123!。;.; 这段文字,我将字重(fontWeight)从100-900都设置了一遍,但看效果好像只有2种字重

从源码中可以看出FontWeight.normal实际就是FontWeight.w400, 而FontWeight.bold实际就是FontWeight.w700

那为啥设置其他的FontWeight.wXXX无效呢?

因为没有配置字体字重!

默认约定:字体文件名与字重对应关系

scss 复制代码
100 - Thin
200 - Extra Light (Ultra Light)
300 - Light
400 - Regular (Normal、Book、Roman)
500 - Medium
600 - Semi Bold (Demi Bold)
700 - Bold
800 - Extra Bold (Ultra Bold)
900 - Black (Heavy)

修改pubspec.yaml配置

P.S. 小米字体文件中未找到字重为800的字体文件,因此w800实际效果和bold,也即是w700一致

yaml 复制代码
fonts:
    - family: MiSans
      fonts:
        - asset: assets/fonts/MiSans-Thin.ttf
          weight: 100
        - asset: assets/fonts/MiSans-ExtraLight.ttf
          weight: 200
        - asset: assets/fonts/MiSans-Light.ttf
          weight: 300
        - asset: assets/fonts/MiSans-Regular.ttf
          weight: 400
        - asset: assets/fonts/MiSans-Medium.ttf
          weight: 500
        - asset: assets/fonts/MiSans-Semibold.ttf
          weight: 600
        - asset: assets/fonts/MiSans-Bold.ttf
          weight: 700
        - asset: assets/fonts/MiSans-Heavy.ttf
          weight: 900

P.S. 字重与文件的对应关系只是弱关联,完全可以不这么对应,只要按设计师效果来对应即可,同时也不是一定要将所有字重都配置上去,应该根据实际需要,用到了就配置,没用到就不配置,毕竟多一个字体文件,最终安装包就会增加几兆

效果

font-weight失效移动安卓处理方法_fontweight500看不出加粗-CSDN博客

Regular、Normal、Medium、Light 对应的font-weight值_字重medium-CSDN博客

字体发虚问题

除开flutter本身的渲染问题之外,我们能做的就是根据实际硬件上的实际感官,选择不同的字号(fontSize)与字重(fontWeight)。

小字号必然要选小字重,大字号必然选大字重

中文与数字或英文同时出现时,文字无法对齐问题

这个应该是由于flutter使用的中文字体和英文字体不一致,导致他们单个的实际行高不一致导致,如上面所示,统一使用同一个字体之后,未出现该问题。

因为中文字体库通常都会包含英文字母以及数字和标点符号,所以,当将默认字体指定为中文字体之后,无论是中文,英文,数字还是标点符号,都会使用同一种字体渲染,那么单个字符的行高就必然一致了。也就不存在无法对齐的问题了。

如何在不同地方,设置默认的统一文字样式

如:导航栏,主题内容,按钮文字

参考上面的代码以及这个截图可以看出,当设置了bodyMedium样式之后普通的Text的样式就都是bodyMedium的样式了。其他样式好像并不会成为什么地方的默认值。那是不是就没用了呢?当然不是,我们依然可以结合他们的语义定义成不同的字体样式,然后所有地方都根据语义,都调用textTheme中的字体公共样式。调用方式:

dart 复制代码
Theme.of(context).textTheme.bodyLarge

// bodyLarge 创建新样式,新样式和bodyLarge的区别是颜色不同
TextStyle newStyle = Theme.of(context).textTheme.bodyLarge!.copyWith(color:Colors.green);

当然,也可以自己定义一个类,将公共样式都定义成这个类的静态属性,然后供其他地方统一调用。

Text和Icon对齐

默认会中线对齐(注意: 文字应该统一使用同一种字体,这能直接避免中文,英文,数字采用不同字体渲染,导致字体大小即使一致,但行高不一致问题)

像这样

加背景色是为了让我们直观的看出来,他们的实际大小,icon图标虽然垂直居中了,但实际高度是内容大小决定的,要调整icon的高度与Text的保持一致,就要设置Icon的size属性。由于这里将Text的fontSize设置成了44,我们想当然的认为将Icon的size也设置成44不就好了,然而实际效果是这样

这里就引出了一个注意点:Text的实际高度默认情况与fontSize是不一致的,Text的实际高度计算公式:Text实际高度 = height * fontSize,height相当于一个缩放因子,当height为1时,fontSize与Text的实际高度保持一致,但这会导致Text中如果存在g,j这类字符,那么将会超出Text的实际高度,可能会导致多行文本的文字重叠,因此height这个缩放因子,至少应该设置成大于1的值,让g,j这类字符不会超出,Text的实际高度。具体设置成多少,应该根据实际使用的字体的观感来决定。为了避免height这个缩放因子的混乱,应该在textTheme中统一设置,或统一定义成一个静态常量

而Icon的size是实际大小,因此,在这个例子中,可以这样设置

不改变Icon大小,达到同样的效果

改变Icon在粉红色框中的位置

Text和TextFormField或TextField对齐

暂未发现无法对齐

相关推荐
江上清风山间明月17 分钟前
Flutter开发的应用页面非常多时如何高效管理路由
android·flutter·路由·页面管理·routes·ongenerateroute
Zsnoin能11 小时前
flutter国际化、主题配置、视频播放器UI、扫码功能、水波纹问题
flutter
早起的年轻人12 小时前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
HappyAcmen12 小时前
关于Flutter前端面试题及其答案解析
前端·flutter
coooliang21 小时前
Flutter 中的单例模式
javascript·flutter·单例模式
coooliang21 小时前
Flutter项目中设置安卓启动页
android·flutter
JIngles12321 小时前
flutter将utf-8编码的字节序列转换为中英文字符串
java·javascript·flutter
B.-1 天前
在 Flutter 中实现文件读写
开发语言·学习·flutter·android studio·xcode
freflying11191 天前
使用jenkins构建Android+Flutter项目依赖自动升级带来兼容性问题及Jenkins构建速度慢问题解决
android·flutter·jenkins
机器瓦力1 天前
Flutter应用开发:对象存储管理图片
flutter