Flutter中初始化时出现错误表情符号的文本小部件

5

我希望在Flutter中的文本小部件中显示表情符号。

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

例如:

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

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

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

然而,只有在首次运行应用程序时,双字母表情符号才会显示为其第一个字符。
即,只有在首次打开应用程序时,剑形图标显示为而不是⚔️
重新加载后问题得到解决,热重新加载/热重启不会再出现这个bug。
我的问题是:
这是一个bug吗?我错过了一些细节吗?为什么只有在首次打开应用程序时才会发生这种情况?
如何从一开始就显示2个大小的emoji?
我正在使用以下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,
      ),
    );
  }
}

1
你在哪个平台上运行?安卓还是IOS? - Abhay Koradiya
问题发生在 Android 模拟器和我的 Android 手机上,它们都运行着 Android 8.1。 - Naslausky
1个回答

5

在创建了这个问题之后,经过多次失败的尝试和没有有效的答案,我在Flutter官方的Github仓库上创建了一个问题

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

第一次呈现dualCharEmoji时,Flutter发现默认字体不能处理2694个字符。[...] 它可以呈现基本的2694个交叉剑字符,但不是2694个FE0F表情符号。

当singleCharEmoji被呈现时,Flutter现在将NotoSansSymbols字体添加到给定给HarfBuzz文本整形器的字体列表中。[...] 并matchFamilyStyleCharacter返回NotoColorEmoji。 Flutter还将此字体添加到缓存中。

下一次引擎尝试呈现dualCharEmoji时,它会向HarfBuzz提供两个缓存字体(NotoSansSymbols和NotoColorEmoji)。 现在,HarfBuzz已经意识到NotoColorEmoji中定义的序列,因此可以识别2694个FE0F表情符号并将其返回给Flutter。

我只引用了讨论的部分内容,您可以在上面链接的问题页面上阅读完整的讨论和解释。
用户提出了两种解决方法:
首先,您可以强制引擎预缓存处理表情符号正确的字体。您可以通过在buildinitState方法中添加以下代码来实现(在构建文本小部件之前运行的任何位置):
import 'dart:ui';

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

这在我的示例项目中有效,但正如问题页面所述:
“然而,这依赖于当前Flutter文本引擎的实现细节,这些细节将来可能会发生变化。”
因此,请注意,这种解决方法随时可能停止工作。
第二种解决方法如下:
“目前的解决方法是在文本样式中列出所需的字体,它将被正确解析。”
这只是为Text Widget提供一个TextStyle属性,其中设置了其fontFamily(或fontFamilyFallback)属性。所选择的字体必须已经支持所有所需字符。这对我也起作用,但我必须从我的计算机(或公共在线包)中包含自定义字体。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接