跳至主要内容

弃用 textScaleFactor,转而使用 TextScaler

摘要

#

为了准备采用Android 14 非线性字体缩放功能,Flutter 框架中所有 textScaleFactor 的出现都已弃用,并由 TextScaler 替换。

背景

#

许多平台允许用户在系统偏好设置中全局放大或缩小文本内容。过去,缩放策略被捕获为一个名为 textScaleFactor 的单个 double 值,因为文本缩放是成比例的:scaledFontSize = textScaleFactor x unScaledFontSize。例如,当 textScaleFactor 为 2.0 且开发者指定的字体大小为 14.0 时,实际字体大小为 2.0 x 14.0 = 28.0。

随着Android 14 非线性字体缩放的引入,与较小的文本相比,较大的文本的缩放比例较小,以防止已经很大的文本过度缩放。 “比例”缩放使用的 textScaleFactor 标量值不足以表示这种新的缩放策略。替换 textScaleFactorTextScaler 的 pull request 引入了一个新的类 TextScaler 来替换 textScaleFactor,以准备此新功能。非线性文本缩放在另一个 pull request 中引入。

变更描述

#

引入一个新的接口 TextScaler,它表示文本缩放策略。

dart
abstract class TextScaler { 
  double scale(double fontSize);
  double get textScaleFactor; // Deprecated. 
}

使用 scale 方法缩放字体大小,而不是 textScaleFactortextScaleFactor getter 提供了一个估计的 textScaleFactor 值,它用于向后兼容目的,并且已经被标记为已弃用,将在 Flutter 的未来版本中移除。

新类已替换 double textScaleFactordouble textScaleFactor -> TextScaler textScaler),在以下 API 中

绘图库

#
受影响的 API错误消息
InlineSpan.build({ double textScaleFactor = 1.0 }) 参数命名参数 'textScaleFactor' 未定义。
TextStyle.getParagraphStyle({ double TextScaleFactor = 1.0 }) 参数命名参数 'textScaleFactor' 未定义。
TextStyle.getTextStyle({ double TextScaleFactor = 1.0 }) 参数'textScaleFactor' 已弃用,不应使用。
TextPainter({ double TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
TextPainter.textScaleFactor getter 和 setter'textScaleFactor' 已弃用,不应使用。
TextPainter.computeWidth({ double TextScaleFactor = 1.0 }) 参数'textScaleFactor' 已弃用,不应使用。
TextPainter.computeMaxIntrinsicWidth({ double TextScaleFactor = 1.0 }) 参数'textScaleFactor' 已弃用,不应使用。

渲染库

#
受影响的 API错误消息
RenderEditable({ double TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
RenderEditable.textScaleFactor getter 和 setter'textScaleFactor' 已弃用,不应使用。
RenderParagraph({ double TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
RenderParagraph.textScaleFactor getter 和 setter'textScaleFactor' 已弃用,不应使用。

Widgets 库

#
受影响的 API错误消息
MediaQueryData({ double TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
MediaQueryData.textScaleFactor getter'textScaleFactor' 已弃用,不应使用。
MediaQueryData.copyWith({ double? TextScaleFactor }) 参数'textScaleFactor' 已弃用,不应使用。
MediaQuery.maybeTextScaleFactorOf(BuildContext context) 静态方法'maybeTextScaleFactorOf' 已弃用,不应使用。
MediaQuery.textScaleFactorOf(BuildContext context) 静态方法'textScaleFactorOf' 已弃用,不应使用。
RichText({ double TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
RichText.textScaleFactor getter'textScaleFactor' 已弃用,不应使用。
Text({ double? TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
Text.rich({ double? TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
Text.textScaleFactor getter'textScaleFactor' 已弃用,不应使用。
EditableText({ double? TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
EditableText.textScaleFactor getter'textScaleFactor' 已弃用,不应使用。

Material 库

#
受影响的 API错误消息
SelectableText({ double? TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
SelectableText.rich({ double? TextScaleFactor = 1.0 }) 构造函数参数'textScaleFactor' 已弃用,不应使用。
SelectableText.textScaleFactor getter'textScaleFactor' 已弃用,不应使用。

迁移指南

#

Flutter 框架提供的 Widgets 已经迁移。仅当您使用上表中列出的任何已弃用符号时,才需要迁移。

迁移公开 textScaleFactor 的 API

#

之前

dart
abstract class _MyCustomPaintDelegate { 
  void paint(PaintingContext context, Offset offset, double textScaleFactor) { 
  }
}

之后

dart
abstract class _MyCustomPaintDelegate { 
  void paint(PaintingContext context, Offset offset, TextScaler textScaler) { 
  }
}

迁移使用 textScaleFactor 的代码

#

如果您目前没有直接使用 textScaleFactor,而是将其传递给接收 textScaleFactor 的其他 API,并且接收 API 已经迁移,那么这相对简单

之前

dart
RichText( 
  textScaleFactor: MediaQuery.textScaleFactorOf(context),
  ...
)

之后

dart
RichText( 
  textScaler: MediaQuery.textScalerOf(context),
  ...
)

如果提供 textScaleFactor 的 API 尚未迁移,请考虑等待迁移后的版本。

如果您希望自己计算缩放后的字体大小,请使用 TextScaler.scale 而不是 * 二元运算符

之前

dart
final scaledFontSize = textStyle.fontSize * MediaQuery.textScaleFactorOf(context);

之后

dart
final scaledFontSize = MediaQuery.textScalerOf(context).scale(textStyle.fontSize);

如果您正在使用 textScaleFactor 缩放不是字体大小的尺寸,则没有将代码迁移到非线性缩放的通用规则,并且可能需要以不同的方式实现 UI。重用 MyTooltipBox 示例

dart
MyTooltipBox( 
  size: chatBoxSize * textScaleFactor,
  child: RichText(..., style: TextStyle(fontSize: 20)),
)

您可以选择使用“有效”文本缩放因子,通过在字体大小 20 上应用 TextScalerchatBoxSize * textScaler.scale(20) / 20,或重新设计 UI 并让 Widget 假设其自己的内在大小。

在 Widget 子树中覆盖文本缩放策略

#

要覆盖 Widget 子树中使用的现有 TextScaler,请覆盖 MediaQuery,如下所示

之前

dart
MediaQuery( 
  data: MediaQuery.of(context).copyWith(textScaleFactor: 2.0),
  child: child,
)

之后

dart
MediaQuery( 
  data: MediaQuery.of(context).copyWith(textScaler: _myCustomTextScaler),
  child: child,
)

但是,很少需要创建自定义 TextScaler 子类。MediaQuery.withNoTextScaling(它创建一个 Widget,完全禁用其子树的文本缩放)和 MediaQuery.withClampedTextScaling(它创建一个 Widget,将缩放后的字体大小限制在范围 [minScaleFactor * fontSize, maxScaleFactor * fontSize] 内)是涵盖需要覆盖文本缩放策略的常见情况的便捷方法。

示例

#

禁用图标字体的文本缩放

之前

dart
MediaQuery(
  data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
  child: IconTheme(
    data: ..,
    child: icon,
  ),
)

之后

dart
MediaQuery.withNoTextScaling(
  child: IconTheme(
    data: ...
    child: icon,
  ),
)

防止内容过度缩放

之前

dart
final mediaQueryData = MediaQuery.of(context);
MediaQuery(
  data: mediaQueryData.copyWith(textScaleFactor: math.min(mediaQueryData.textScaleFactor, _kMaxTitleTextScaleFactor),
  child: child,
)

之后

dart
MediaQuery.withClampedTextScaling(
  maxScaleFactor: _kMaxTitleTextScaleFactor,
  child: title,
)

禁用非线性文本缩放

如果您想暂时选择退出 Android 14 上的非线性文本缩放,直到您的应用完全迁移,请在应用 Widget 树的顶部放置一个修改后的 MediaQuery

dart
runApp(
  Builder(builder: (context) {
    final mediaQueryData = MediaQuery.of(context);
    final mediaQueryDataWithLinearTextScaling = mediaQueryData
      .copyWith(textScaler: TextScaler.linear(mediaQueryData.textScaler.textScaleFactor));
    return MediaQuery(data: mediaQueryDataWithLinearTextScaling, child: realWidgetTree);
  }),
);

此技巧使用已弃用的 textScaleFactor API,并且一旦它从 Flutter API 中移除,它将停止工作。

时间线

#

包含于版本:3.13.0-4.0.pre
稳定版发布:3.16

参考

#

API 文档

相关问题

相关 PR