【问题标题】:Text widget with wrong emoji on initialization in Flutter在 Flutter 中初始化时带有错误表情符号的文本小部件
【发布时间】:2020-03-23 16:01:48
【问题描述】:

我想使用 Flutter 在文本小部件中显示表情符号。

当我从互联网复制一个示例表情符号时,其中一些在我的 IDE 中显示为 2 个字符。

例如:

static String dualCharEmoji = "⚔️";
static String singleCharEmoji = "????";

当我在文本小部件中使用此变量时,它们都可以正常工作:

Text("⚔️",)
Text("????",)

但是,只有在首次运行应用程序时,双字符表情符号才会显示为其第一个字符。

即只有在第一次打开应用程序时,剑图标才会显示为⚔,而不是⚔️

重新加载后它会被修复,并且热重新加载/热重启不会再次使其出现错误。

我的问题是:

这是一个错误吗?我在这里遗漏了一些细节吗?为什么只在第一次打开应用时出现?

如何从一开始就显示 2 大小的表情符号?

我正在使用以下 Flutter 版本:

>flutter --version
Flutter 1.9.1+hotfix.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision cc949a8e8b (9 weeks ago) • 2019-09-27 15:04:59 -0700
Engine • revision b863200c37
Tools • Dart 2.5.0

请参阅下面的最小可重现示例:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static String dualCharEmoji = "⚔️";
  static String singleCharEmoji = "????";
  String text = dualCharEmoji;
  int count = 0;
  void swapText() {
    setState(() {
      if (count % 2 == 0)
        text = singleCharEmoji;
      else
        text = dualCharEmoji;
      count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              text,
              style: TextStyle(fontSize: 50),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: swapText,
      ),
    );
  }
}

【问题讨论】:

  • 您在哪个平台上运行?安卓还是IOS?
  • 问题发生在安卓模拟器和我的安卓8.1安卓手机上

标签: flutter dart emoji


【解决方案1】:

在创建了这个问题,做了很多不成功的尝试,并且没有有效的答案之后,我在 Flutter 的官方 Github 存储库上创建了一个 issue。

在我展示我的问题后,一位用户解释说这是一个与 Flutter 如何渲染和缓存字体有关的错误,以防默认字体无法正确处理某些字符:

第一次渲染 dualCharEmoji 时 Flutter 看到默认字体不处理 2694 字符。 [...]它可以渲染基本的 2694 交叉剑字符,但不能渲染 2694 FE0F 表情符号。

当 singleCharEmoji 被渲染时,Flutter 现在将 NotoSansSymbols 字体包含在 HarfBuzz 文本整形器的字体列表中。[...] 并且 matchFamilyStyleCharacter 返回 NotoColorEmoji。 Flutter 也会将此字体添加到缓存中。

下次引擎尝试渲染 dualCharEmoji 时,它会向 HarfBuzz 提供缓存的字体(NotoSansSymbols 和 NotoColorEmoji)。现在 HarfBuzz 知道 NotoColorEmoji 中定义的序列,它可以识别 2694 FE0F 表情符号并将其返回给 Flutter。

我在这里只引用了讨论的一部分。您可以在我上面链接的问题页面上阅读完整的讨论和解释。

用户提出了一些解决方法,即两个:

首先,您可以强制引擎预先缓存正确处理表情符号的字体。您可以通过在build 或initState 方法(在构建文本小部件之前运行的任何地方)中添加以下代码来做到这一点:

import 'dart:ui';

ParagraphBuilder pb = ParagraphBuilder(ParagraphStyle(locale: window.locale));
pb.addText('\ud83d\ude01');  // smiley face emoji
pb.build().layout(ParagraphConstraints(width: 100));

这适用于我的示例项目,但如问题页面所述:

不过,这取决于当前 Flutter 文本引擎的实现细节,未来可能会发生变化。

因此请注意,此解决方法可能会在任何给定时间停止工作。

第二种解决方法如下:

目前的解决方法是在文本样式中列出所需的字体,它将被正确解析。

这只是将TextStyle 属性赋予文本小部件,并设置其fontFamily(或fontFamilyFallback)属性。所选字体必须已经支持所需的所有字符。这也对我有用,但是我必须从我的计算机(或公共在线包)中包含一个自定义字体。

【讨论】:

    猜你喜欢
    • 2019-12-08
    • 2017-12-09
    • 2020-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    相关资源
    最近更新 更多