跳至主要內容

棄用 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 純量值不足以表示這種新的縮放策略。 textScaleFactor 替換為 TextScaler 的 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 textScaleFactor (double textScaleFactor -> TextScaler textScaler)

繪圖程式庫

#
受影響的 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' 已棄用,不應使用。

小工具程式庫

#
受影響的 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,為其子樹完全停用文字縮放) 和 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 上暫時退出非線性文字縮放,直到您的應用程式完全遷移為止,請將修改後的 MediaQuery 放在您的應用程式 Widget 樹的頂部

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