概述

#

為了支援 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,它表示一種文字縮放策略。

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

使用 scale 方法來縮放字型大小,而不是 textScaleFactortextScaleFactor getter 提供了一個估計的 textScaleFactor 值,它僅用於向後相容目的,並且已標記為棄用,將在 Flutter 的未來版本中移除。

新類已替換了以下 API 中的 double textScaleFactordouble 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

#

之前

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)),
)

您可以選擇使用“有效”文字比例因子,方法是將 TextScaler 應用於字型大小 20:chatBoxSize * 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 子樹停用文字縮放的 widget)和 MediaQuery.withClampedTextScaling(建立一個將縮放後的字型大小限制在 [minScaleFactor * fontSize, maxScaleFactor * fontSize] 範圍內的 widget)是方便的方法,它們涵蓋了需要覆蓋文字縮放策略的常見情況。

示例

#

為圖示字型停用文字縮放

之前

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