Flutter 上默認的文本和字體知識點

咱們都知道在 Flutter 中能夠經過 fontFamily 來引入第三方字體,例如一般會將 svg 圖標轉換爲 iconfont.ttf 來實現矢量圖標的入,而通常狀況下咱們是不會設置 fontFamily 來使用第三方字體, 那默認狀況下 Flutter 使用的是什麼字體呢?android

會出現這個疑問,是由於有一天設計給我發了下面那張圖,問我 「爲何應用在蘋果平臺上的英文使用的是 PingFang SC 字體而不是 .SF UI Display ? 正以下圖所示,它們的 G 字母在顯示效果上會有所差別,好比 平方的 G 有明顯的轉折線。git

這時候我不由產生的好奇,在 Flutter 中引擎默認到底是如何選擇字體?github

經過官方解釋,在 typography.dart 源碼中能夠看到,後端

  • Flutter 默認在 Android 上使用的是 Roboto 字體;
  • 在 iOS 上使用的是 .SF UI Display 或者 .SF UI Text 字體。

The default font on Android is Roboto and on iOS it is .SF UI Display or .SF UI Text (SF meaning San Francisco). If you want to use a different font, then you will need to add it to your app.bash

那理論上在 iOS 使用的就是 .SF UI Display 字體纔對,由於以下源碼所示,在 Typography 中當 platformiOS 時,使用的就是 Cupertino 相關的 TextTheme,而 Typography 中的 whiteblack 屬性最終會應用到 ThemeDatadefaultTextThemedefaultPrimaryTextThemedefaultAccentTextTheme 中,因此應該是使用 .SF 相關字體纔會,爲何會顯示的是 PingFang SC 的效果?網絡

factory Typography({
    TargetPlatform platform = TargetPlatform.android,
    TextTheme black,
    TextTheme white,
    TextTheme englishLike,
    TextTheme dense,
    TextTheme tall,
  }) {
    assert(platform != null || (black != null && white != null));
    switch (platform) {
      case TargetPlatform.iOS:
        black ??= blackCupertino;
        white ??= whiteCupertino;
        break;
      case TargetPlatform.android:
      case TargetPlatform.fuchsia:
        black ??= blackMountainView;
        white ??= whiteMountainView;
    }
    englishLike ??= englishLike2014;
    dense ??= dense2014;
    tall ??= tall2014;
    return Typography._(black, white, englishLike, dense, tall);
  }
複製代碼

爲了搞清不一樣系統上字體的區別,在查閱了資料後可知:app

  • 默認在 iOS 上:svg

    • 中文字體:PingFang SCpost

    • 英文字體:.SF UI Text.SF UI Display測試

  • 默認在 Android 上:

    • 中文字體:Source Han Sans / Noto

    • 英文字體:Roboto

也就是就 iOS 上除了 .SF 相關的字體外,還有 PingFang 字體的存在,這時候我忽然想起在以前的 《Flutter完整開發實戰詳解(十7、 實用技巧與填坑二)》 中,由於國際化多語言在 .SF 會出現顯示異常,因此使用了 fontFamilyFallback 強行指定了 PingFang SC

getCopyTextStyle(TextStyle textStyle) {
    return textStyle.copyWith(fontFamilyFallback: ["PingFang SC", "Heiti SC"]);
  }
複製代碼

終於破案了,由於當 fontFamily 沒有設置時,就會使用 fontFamilyFallback 中的第一個值將做爲首選字體,而在 fontFamilyFallback 中是順序匹配的,當fontFamilyfontFamilyFallback 二者都不提供,則將使用默認平臺字體。

而在 1.12.13 版本下測試發現 .SF 致使的問題已經修復了,因此只須要將 fontFamilyFallback 相關的代碼去除便可。

那在 iOS 上使用 .SF 字體有什麼好處? 按照網絡上的說法是:

SF Text 的字距及字母的半封閉空間,好比 "a"! 上半部分會更大,因其可讀性更好,適用於更小的字體; SF Display 則適用於偏大的字體。具體分水嶺就是 20pt , 即字體小於 20pt 時用 Text ,大於等於 20pt 時用 Display

更棒的是因爲 SF 屬於動態字體,TextDisplay 兩種字體族是系統動態匹配的,也就是說你不用費心去本身手動調節,系統自動根據字體的大小匹配這兩種顯示模式。

那能不能在 Android 上也使用.SF 字體呢?按照官方的說法:

  • 在使用 Material package 時,在 Android 上使用的是 ·Roboto font· ,而 iOS 使用的是 San Francisco font(SF)
  • 在使用 Cupertino package 時,默認主題始終使用 San Francisco font(SF)

可是由於 San Francisco font license 限制了該字體只能在 iOS、macOS 或 tvOS 上運行使用,因此若是使用了 Cupertino 主題的話,在 Android 上運行時使用 fallback font。

因此你以爲能不能在 Android 上使用?

最後再補充下,在官方的 architecture 中有提到,在 Flutter 中的文本呈現邏輯是有分層的,其中:

  • 衍生自 Minikin 的 libtxt 庫用於字體選擇,分隔行等;
  • HartBuzz 用於字形選擇和成型;
  • Skia做爲 渲染 / GPU後端;
  • 在 Android / Fuchsia 上使用 FreeType 渲染,在 iOS 上使用CoreGraphics 來渲染字體 。

那讀完本篇,你奇奇怪怪的知識點有沒有增長?

相關文章
相關標籤/搜索