为提高可访问性,如何缩放嵌套的RichText小部件

8

我在处理 RichText 如何处理包含其他RichText实例的嵌套跨度。只要用户不更改手机的默认字体大小,它就可以正常工作。但是如果他们已经更改了显示字体大小,事情就开始出错了。

考虑这样一个情况,我正在解析一些类似于HTML的内容:

<underline><italic><bold>xxxxx</bold></italic></underline>

从概念上讲,这可以建模为一个TextSpan内部包含另一个TextSpan,因此我可能会有一些人为的代码,看起来像:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final inputText = 'The quick brown fox jumped over the lazy dog. The quick brown fox jumped over the lazy dog.';
    final initialSpan = TextSpan(text: inputText, style: TextStyle(color: Colors.black));

    final boldText = _buildStyledElement(context, initialSpan, Style.bold);
    final boldItalised = _buildStyledElement(context, WidgetSpan(child: boldText), Style.italic);
    final boldItalisedUnderlined = _buildStyledElement(context, WidgetSpan(child: boldItalised), Style.underline);

    return new Scaffold(
      appBar: AppBar(title: Text('')),
      body: Column(
        children: [
          Text(inputText), // a simple baseline to compare
          boldText,
          boldItalised,
          boldItalisedUnderlined,
        ],
      ),
    );
  }

  RichText _buildStyledElement(BuildContext context, InlineSpan span, Style style) {
    // note we're not applying the style because it isn't important... the style parameter
    // is just a means of wrapping our heads around a real-world example of nesting
    return RichText(text: span);
  }
}

如您所见,左侧的文本字体大小看起来很好,但右侧三个RichText用于调整手机字体大小时无法缩放。

No scaling

这很容易解释...因为RichText的默认缩放因子是1.0,所以没有缩放。让我们通过更改创建代码来修复它:

return RichText(text: span, textScaleFactor: MediaQuery.of(context).textScaleFactor);

正如你在下面看到的,普通字体看起来仍然不错,但是哇...由于RichText嵌套(我假设它将比例因子应用于已经缩放的子元素),事情会迅速扩大。

根据设备缩放比例变化

现在,我发现的一件事是,如果我允许所有的RichText小部件使用1.0的比例因子创建,然后用设备的比例因子包装最外层的RichText,它几乎可以工作。例如,从_buildStyledElement中删除缩放并将此行添加到主Column小部件中:

RichText(text: WidgetSpan(child: boldItalisedUnderlined), textScaleFactor: MediaQuery.of(context).textScaleFactor),

正常字体看起来很好,而且可以实际缩放到正确的大字体大小。然而,现在换行已经破裂了。

只缩放外部小部件

我认为这是因为子RichText小部件计算的大小(因为它们使用1.0的比例因子)与使用媒体查询的比例因子计算的总空间不匹配。

所以...我的问题是是否有一种方法可以通过嵌套的RichText实例使其正常工作。我知道对于这个特定的例子可能有其他选项...但我谈论的是RichText小部件嵌入其他RichText小部件的一般情况。

非常感谢您提出任何想法。抱歉我的帖子很长。


顺便说一下,我刚刚提出了一个 bug:https://github.com/flutter/flutter/issues/59316 - Craig Edwards
1个回答

3

虽然没有确定的解决方案,但我发现一个特别有用的解决方法:

您需要将Html Widget的文本比例因子设置为固定值1,并选择HTML上的平均文本的默认字体大小,然后将其乘以屏幕的当前比例因子(而不是手动固定的比例因子)。

class ExampleWidget extends StatelessWidget {
  final String data;
  ExampleWidget({this.data});
  @override
  Widget build(BuildContext context) {
    double scaleFactor = MediaQuery.of(context).textScaleFactor;
    int standardFontSize = 14;
    int h3FontSize = 18;
    return MediaQuery(
      data: MediaQueryData(textScaleFactor: 1),
      child: Html(
        data: data,
        style: {
          'body': Style(fontSize: FontSize(standardFontSize * scaleFactor)),
          'h3': Style(fontSize: FontSize(h3FontSize * scaleFactor))
          // other header fonts...
        },
      ),
    );
  }
}

缺点是每次需要新的字体大小时都需要手动实现,但它可能会解决一个紧急问题。

我可以看出这可能解决缩放问题...在这种情况下,您的文本是否正确换行?我所有的调查都发现将最内层比例因子设置为1.0,然后在单个(正确的)MediaQuery比例因子中换行将导致a)正确缩放的文本,但b)文本不会在正确的边界处换行。当然,我还没有测试特定更改字体大小的技术...我只是在操作textScaleFactor。您的技术绝对看起来像一个相当不错的解决方法。 - Craig Edwards
是的,由于文本边界不再超出屏幕,所以包装工作正常。 - Aylan Boscarino

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