弃用 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
标量值不足以表示这种新的缩放策略。在 用 TextScaler
替换 textScaleFactor
的 pull request 中,引入了一个新类 TextScaler
来替换 textScaleFactor
,为这个新功能做准备。非线性文本缩放是在另一个 pull request 中引入的。
变更说明
#引入了一个新接口 TextScaler
,它表示一种文本缩放策略。
abstract class TextScaler {
double scale(double fontSize);
double get textScaleFactor; // Deprecated.
}
使用 scale
方法来缩放字体大小,而不是 textScaleFactor
。textScaleFactor
getter 提供了一个估计的 textScaleFactor
值,它仅用于向后兼容目的,并且已标记为弃用,将在 Flutter 的未来版本中移除。
新类已替换了以下 API 中的 double textScaleFactor
(double textScaleFactor
-> TextScaler textScaler
):
Painting 库
#受影响的 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' 已弃用,不应使用。 |
Rendering 库
#受影响的 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 框架提供的 widget 已迁移。仅在您使用上表中列出的任何已弃用符号时才需要迁移。
迁移暴露 textScaleFactor
的 API
#之前
abstract class _MyCustomPaintDelegate {
void paint(PaintingContext context, Offset offset, double textScaleFactor) {
}
}
之后
abstract class _MyCustomPaintDelegate {
void paint(PaintingContext context, Offset offset, TextScaler textScaler) {
}
}
迁移使用 textScaleFactor
的代码
#如果您当前不直接使用 textScaleFactor
,而是将其传递给接收 textScaleFactor
的其他 API,并且接收 API 已迁移,那么迁移相对简单。
之前
RichText(
textScaleFactor: MediaQuery.textScaleFactorOf(context),
...
)
之后
RichText(
textScaler: MediaQuery.textScalerOf(context),
...
)
如果提供 textScaleFactor
的 API 未迁移,请考虑等待迁移版本。
如果您希望自己计算缩放后的字体大小,请使用 TextScaler.scale
,而不是 *
二元运算符。
之前
final scaledFontSize = textStyle.fontSize * MediaQuery.textScaleFactorOf(context);
之后
final scaledFontSize = MediaQuery.textScalerOf(context).scale(textStyle.fontSize);
如果您使用 textScaleFactor
来缩放非字体大小的尺寸,没有通用的规则来将代码迁移到非线性缩放,这可能需要重新实现 UI。重用 MyTooltipBox
示例
MyTooltipBox(
size: chatBoxSize * textScaleFactor,
child: RichText(..., style: TextStyle(fontSize: 20)),
)
您可以选择使用“有效”文本比例因子,方法是将 TextScaler
应用于字体大小 20:chatBoxSize * textScaler.scale(20) / 20
,或者重新设计 UI,让 widget 假定其自身的内在大小。
在 widget 子树中覆盖文本缩放策略
#要覆盖 widget 子树中使用的现有 TextScaler
,请像这样覆盖 MediaQuery
:
之前
MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 2.0),
child: child,
)
之后
MediaQuery(
data: MediaQuery.of(context).copyWith(textScaler: _myCustomTextScaler),
child: child,
)
然而,创建自定义 TextScaler
子类的情况很少。MediaQuery.withNoTextScaling
(创建一个为子 widget 子树禁用文本缩放的 widget)和 MediaQuery.withClampedTextScaling
(创建一个将缩放后的字体大小限制在 [minScaleFactor * fontSize, maxScaleFactor * fontSize]
范围内的 widget)是方便的方法,它们涵盖了需要覆盖文本缩放策略的常见情况。
示例
#为图标字体禁用文本缩放
之前
MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
child: IconTheme(
data: ..,
child: icon,
),
)
之后
MediaQuery.withNoTextScaling(
child: IconTheme(
data: ...
child: icon,
),
)
防止内容过度缩放
之前
final mediaQueryData = MediaQuery.of(context);
MediaQuery(
data: mediaQueryData.copyWith(textScaleFactor: math.min(mediaQueryData.textScaleFactor, _kMaxTitleTextScaleFactor),
child: child,
)
之后
MediaQuery.withClampedTextScaling(
maxScaleFactor: _kMaxTitleTextScaleFactor,
child: title,
)
禁用非线性文本缩放
如果您想暂时退出 Android 14 的非线性文本缩放,直到您的应用完全迁移,请在应用 widget 树的顶部放置一个修改后的 MediaQuery
。
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 文档
TextScaler
MediaQuery.textScalerOf
MediaQuery.maybeTextScalerOf
MediaQuery.withNoTextScaling
MediaQuery.withClampedTextScaling
相关问题
相关 PR