一份給 Android 開發者的字體排印指南

本文搬運自字體博客 Fate/Typo. 譯者 Chao Shell. 譯文鏈接:

一份給 Android 開發者的字體排印指南?

fatetypo.xyz圖標

原文:The Android Developers Guide to Better Typography

作者:Rod Sheeter

時間:2017 年 12 月 6 日

譯按:去年更新的 Android Oreo,帶來了 「可下載字體」 的新特性,給予開發者更靈活的字體配置方式,縮減 APK 文件大小和共享字體以環節存儲空間佔用對設備廠商也是利好。Google Design 的這篇文章以一款應用程序——Plaid 為例,介紹了具體的字體排印案例。

字體排印可以使一款應用程序的吸引力和可用性發生重大變化。現在,Android 開發者可以使用 Google Fonts 中的字體,其簡單,高效,並提供了一種新的字體排印方式。

儘管每一位開發者都知道,「設計」在用戶體驗中扮演著重要角色 ,它可能是一款應用成功或失敗的關鍵因素。但在面對推進發布,逃避集成自定義字體的複雜性或是看似神秘的選擇字體的藝術時,還是有著直接使用默認字體的誘惑。

幸運的是,Android Studio 支持新的「可下載的字體」功能,可以更輕鬆地為應用程序構建獨特的字體排版。此功能可以輕鬆地將完整的 Google Fonts 中自由、可靠且高質的字體輕鬆地在 JellyBean 及更高版本(SDK 16+)中自定義字體排印。

除了美學改進之外,「可下載的字體」還可以減小 APK 文件的整體大小,並減少內存佔用,因為已下載的字體將在所有的應用程序之間共享。而因為不需要預先捆綁字體,APK 文件會進一步更減小。如果一個應用程序從 Google Fonts 下載了一款字體,Android 會將其保存在存儲空間中,以便其他應用程序也可以使用它,而無需佔用任何額外的存儲空間。就像我們網站的 API 直接向網站提供字體一樣,人們使用 Google 字體越多,共享的延遲就越大。

在本教程中,我們以示例應用程序為例,通過以 Google Fonts 中的字體替換具有的特性和動態範圍樣式的內容的標準字體,來改善字體排印。我們將使用一款名為 Alegreya 的字體,作為一款「超級字體家族」,其具有廣泛的樣式、字重和變體。這意味著我們將有大量的字體排印的選擇來微調界面外觀。

我們使用的示例應用程序是由 Nick Butcher 開發的 Plaid,這是一款發布 Material Design 相關新聞的可滾動 Feed 應用。這些全出血 (譯註 1) 的圖塊,你可以點擊或點擊以展開進入 dribble 的頁面,其中有「喜歡」和「瀏覽」的統計信息。

本教程面向開發者,但它也解釋了一些決定設計背後的「原因」,因此請注意這兩點!

在我們開始之前

首先安裝 Android Studio 3.0,然後從 Github 中 clone「Plaid」項目並 checkout b76937,這是我們將用於本教程的版本:

git clone https://github.com/rsheeter/plaid.gitcd plaidgit checkout b76937

現在,在 Android Studio 3.0 中打開該項目。

為了使用 Google Fonts 提供程序,你必須安裝 Google Play 服務 12 版以上。如果你正在使用升級到最新系統的設備,則可以跳過; 但如果你使用的是 Android Studio 啟動的模擬器,則可能使用的是舊版 Google Play 服務。從 Android Studio 更新 Android 虛擬設備,請按照下列步驟操作。

1. 創建一個帶有 Play Store 的虛擬設備(Tools > Android > AVD Manager),Play Store 中的圖標表示為:

2. 在 Android Studio 中啟動一個虛擬設備。打開模擬器屏幕右側的「Extended Controls」,點擊垂直按鈕面板底部的「」圖標:

3. 選擇 Google Play 並檢查版本號。如果您運行的是 11.2 版或更低版本,請點擊 Update 按鈕,這將引導至 Play Store,然後點擊或點擊綠色的 Update 按鈕:

4. 現在已更新至 11.2 或更高版本,該設備將支持可下載的字體。

更新 About 頁面

首先,我們來更新 About 頁面。頁面下半部分的「正文」段落目前被設置為 Roboto Regular,這是一款無襯線字體,頁面上半部分的標題被設置為 Roboto Mono Regular。讓我們將其轉換為襯線字體 Alegreya,這是一種充滿活力的當代設計,其靈感來自書法字母,具有充滿活力和節奏多變的特點。 Alegreya 是一款「超級字體家族」,最初用於文學作品排印,包括襯線和無襯線的姊妹字體家族。

標題文字就像「英雄形象」,這一圖像能將人引導到頁面中。並能定義情感語氣。這裡的標題的字母作為「蒙版」,將薄荷綠的前景切掉,鏤空顯示後面的圖像。從 Roboto Mono Regular 改為 Alegreya Black,將為背景圖像提供更大的鏤空區域,更加明亮。

設置「About Activity」文本

由於「About Activity」文本目前為「default」文本樣式,即 Roboto Regular,我們必須手動設置為另一個:

  1. 打開 app/src/main/res/layout/about_plaid.xml
  2. 選擇 Design 面板
  3. Component Tree 面板中, 打開 about_description
  4. Attributes 面板中, 打開 fontFamily 下拉列表並選擇 More Fonts… (你可能需要點擊 View all attributes才能看到 fontFamily
  5. 選擇字體家族 Alegreya
  6. 選擇字體樣式 Regular

按照步驟 1-6 設置「About Activity」文本的樣式

Android Studio 已經配置了我們的應用程序以從 Google Fonts「提供程序」中檢索字體。為此,它對我們的源碼樹進行了一些更改:

app/src/main/res/font/ (查看更多)

這個新目錄包含描述字體資源的 XML 文件。在這種情況下,它提供了從 Google Fonts 提供程序載入字體的說明。

app/src/main/res/values/font_certs.xml (查看更多)

為確保字體請求僅由可信方回應,該文件指定字體提供程序的簽名。

app/src/main/res/values/preloaded_fonts.xml (查看更多)

這是在安裝和更新過程中載入的字體列表,以確保這些字體在啟動應用程序時可用。

你可以在 commit a1e711c 中看到此步驟的示例 diff。

更新裁剪文本視圖

文本樣式目前是 Roboto Mono Regular。讓我們繼續上一步的更改:

7. 在 Design 視圖中, 選擇「CutoutTextView」

8. 打開「fontFamily」下拉菜單並選擇「More Fonts…」

9. 選擇字體家族「Alegreya」

10. 選擇字體樣式「Black」

11.(對於步驟 11, 請見下文)

按照步驟 7-11 更新 CutoutTextView

如果你現在嘗試此操作,字體仍然是 Roboto Regular,而不是 Alegreya Black,原因是默認情況下,聲明性字體是非同步獲取的(了解更多)。完成之後,系統將嘗試使用 setTypeface 更新 TextView 的字體,但這會因 CutoutTextView 不會擴展 TextView 而失敗。

但是,CutoutTextView 並沒有實現 fontFamily 屬性(這裡)。如果我們將字體提取標記為 blocking,那麼 fontFamily 將在我們請求時做好準備。如果我們不將其標記為 blocking,那麼為 fontFamily 返回的值將不可用。(我們也可以編寫自己的非同步獲取,但我們稍後再談。)

  1. 打開 app/src/main/res/font/alegreya.xmlalegreya-black.xml,然後將此屬性追加到 <font-family> 元素的末尾:

app:fontProviderFetchStrategy="blocking"

現在試試吧!(你可以在 commit f1c997 看到此步驟的示例 diff)

更新 text-size

看看「About」文本,它在灰色背景上略顯灰色。 Alegreya 是一款襯線字體,具有較高的「筆畫差異(stroke modulation)」 (譯註2),意味著字母從最粗到最細的字體都有很大的不同。這導致總體視覺對比度較低。字體中的細微變化可能會使其看起來模糊,尤其是在小字型大小的情況下。

為了緩解這個問題,我們將這個段落的 text-size 16sp 增加到 18sp。這將增加文本與其背景的明顯對比。

about_plaid.xmlTextView 使用 TextAppearance.About 樣式。要將文本大小從 16sp 更改為 18sp,可編輯 app/src/main/res/values/styles.xml 這一部分:

<style name="TextAppearance.About" parent="@android:style/TextAppearance.Material.Body1"> ...- <item name="android:textSize">16sp</item>+ <item name="android:textSize">18sp</item> </style>

你可以在 github.com/rsheeter/plaid/commit/4dda25 上看到此步驟的示例 diff。

更新應用標題

接下來,我們將通過編程方式提取字體,以更改我們的應用程序的標題。標題目前為應用了「小型大寫字母」的 OpenType 特性的 Roboto。我們還使用了額外的「tracking」來分隔這些字母。

(這個細節是借鑒了書籍排印的慣例,章節標題常位於頁面的頂部並採用小型大寫字母。了解更多關於字體排印的信息,可查閱 Jan Middendorp 的《Shaping Text》一書。)

非同步獲取會因 Toolbar 不是 TextView 而失敗,就像 CutoutTextView 不是 TextView 一樣。另外,Toolbar 無法實現 fontFamily 屬性,所以我們不能只設置 blocking 來修復。

相應的,我們可以嘗試以編程方式獲取和賦值字體。 在 app/src/main/java/io/plaidapp/ui/HomeActivity.java 中使用 FontsContractCompat (參考) 按照以下四個步驟請求字體。

1. 我們需要一個線程等待字體,聲明一個變數以保存:

private Handler fontHandler

2. 添加一個 Method 來管理字體處理線程:

private Handler getFontHandlerThread() { if (fontHandler == null) { HandlerThread handlerThread = new HandlerThread("fonts"); handlerThread.start(); fontHandler = new Handler(handlerThread.getLooper()); } return fontHandler;}

3. 添加一個 Method 將 Typeface (參考 ) 應用於 Toolbar:

private void styleToolbar(Typeface typeface) { // this is gross but toolbar doesnt expose its children for (int i = 0; i < toolbar.getChildCount(); i++) { View rawView = toolbar.getChildAt(i); if (!(rawView instanceof TextView)) { continue; }TextView textView = (TextView) rawView; textView.setTypeface(typeface); }}

4. 在 onCreate 中,從字體提供程序啟動非同步獲取:

@Overrideprotected void onCreate(Bundle savedInstanceState) { ... FontRequest fontRequest = new FontRequest("com.google.android.gms.fonts", "com.google.android.gms", "name=Alegreya", R.array.com_google_android_gms_fonts_certs); FontsContractCompat.FontRequestCallback toolbarFontCallback = new FontsContractCompat.FontRequestCallback() { @Override public void onTypefaceRetrieved(Typeface typeface) { // If we got our font apply it to the toolbar styleToolbar(typeface); } @Override public void onTypefaceRequestFailed(int reason) { Log.w(TAG, "Failed to fetch Toolbar font: " + reason); } }; // Start async fetch on the handler thread FontsContractCompat.requestFont(this, fontRequest, toolbarFontCallback, getFontHandlerThread());

切換到 Alegreya Sans SC Black

回到主頁面,我們注意到標題看起來有點過於細。像許多襯線字體一樣,Alegreya 的筆畫差異導致視覺對比度較低,尤其是當與無襯線字體相比時。

幸運的是,Alegreya 是一款「超級字體家族」,其襯線和無襯線樣式都有多種字重,適配這兩種樣式的字體並使用不同的字重來構建界面,以內容描繪 UI。讓我們試試 Alegreya Sans Small Caps (SC) 吧。

Alegreya 的小型大寫字母本身就較小,但我們可以通過增加其字重來改善這一點。試試 Black (900) 的字重。

1. 複製 res/font/alegreya.xml 以創建 res/font/font/alegreya_sans_sc_black.xml

2. 編輯 alegreya_sans_sc_black.xml 以更改 app:fontProviderQueryname=Alegreya Sans SC&amp;weight=900

3. 編輯 res/values/preloaded_fonts.xml 以添加新字體:

4. 在 HomeActivity.java 中指定新的 query:

FontRequest fontRequest = new FontRequest("com.google.android.gms.fonts", "com.google.android.gms", "name=Alegreya Sans SC&weight=900", R.array.com_google_android_gms_fonts_certs);

將 Alegreya Black 更改為 Bold

再來看看主頁上的標題

Black 字重在這裡有點太強烈了,所以讓我們把它降為 Bold (700)。

1. 將 alegreya_sans_sc_black.xml 重命名為 alegreya_sans_sc_bold.xml 並編輯以更改 app:fontProviderQueryname=Alegreya Sans SC&amp;weight=700

2. 在 HomeActivity.java 中更新 query:

FontRequest fontRequest = new FontRequest("com.google.android.gms.fonts", "com.google.android.gms",- "name=Alegreya Sans SC&weight=900",+ "name=Alegreya Sans SC&weight=700", R.array.com_google_android_gms_fonts_certs);

您可以在 commit ac55478 處看到應用程序最終狀態的示例 diff(使用了 Alegreya Sans SC Bold)。看看項目的比較吧。

更新 Dribble 視圖

要進入應用程序中的「dribble」視圖,請點擊或單擊主屏幕上的卡片。再一次的,我們用 Alegreya Black 替換 Roboto Mono Regular。

app/src/main/res/layout/dribbble_shot_title.xml 中,請注意標題和描述在使用 @style/TextAppearance.DribbbleShotTitle@style/TextAppearance.DribbbleShotDescription 設置樣式。在 app/src/main/res/values/styles.xml 中找到它們(提示:Ctrl+點擊)。現在改變字體:

- <item name="android:fontFamily">monospace</item>+ <item name="android:fontFamily">@font/alegreya_black</item>

你可以在 commit 0e53b56 查看示例 diff。

更改數字樣式

「dribble」的視圖還有一點需要改進。

「喜歡」和「瀏覽」按鈕使用了所謂的「舊式數字」。這一設計是為了與文本段落中的小寫拉丁字母混排。但是,對於舊式數字本身而言,看起來不合適,因為他們的降部 (譯註 3) 有時會掛在其他文本的基線 (譯註 4)之下。

相應的,我們使用 lnum 特性。這告訴應用程序使用「齊線數字」,因為它們被設計為與大寫字母相同的高度,所以更加易讀。(了解更多內容,查看 Typekit)

通過查看 app/src/main/res/layout/dribbble_shot_description.xml,我們可以看到,「喜歡」和「瀏覽」計數器的樣式是 @style/Widget.Plaid.InlineActionButton

app/src/main/res/values/styles.xml 中找到 @style/Widget.Plaid.InlineActionButton(提示:Ctrl+點擊)。

現在添加一條指令來為這些計數器使用齊線數字:

<style name="Widget.Plaid.InlineActionButton" parent="@android:style/Widget.Material.Button"> <item name="android:gravity">center_horizontal</item> <item name="android:textAppearance">@style/TextAppearance.CommentAuthor</item> <item name="android:drawablePadding">@dimen/spacing_micro</item> <item name="android:background">?android:selectableItemBackgroundBorderless</item>+ <item name="android:fontFeatureSettings">lnum</item></style>

您可以在 commit 4dda25 看到一個示例 diff。

結論

經過這些簡單的更改後,並藉助了 Google 的免費開源字體庫, 我 fork 的 Plaid 應用程序 現在具有了更醒目和更具功能性的字體排印。通過 Android 新的可下載字體功能,你可以使用 Google Fonts 中的任何字體來自定義應用中的字體排印。正如本教程所述,只需進行一些更改,就可以在易讀性和用戶體驗方面帶來真正的改變。希望對你有所幫助!

(譯)註:

  1. 全出血:出血為印刷出版專有名詞,指在列印中超出紙張裁剪的邊緣部分,也就是需要裁剪的區域。這裡的全出血意思是作品圖塊與屏幕邊緣之間沒有空隙。
  2. 筆畫差異(stroke modulation):difference in stroke width within a letterform; also called stroke modulation. 字形內部筆畫寬度的差異,亦稱作「contrast」。
  3. 降部:descender,如 g、j、p、q、y 從基線向下延伸的部分。
  4. 基線:baseline,貼著如大寫字母「A」和小寫字母「b」下部的那一條「線」

推薦閱讀:

字談字暢 068:無體不成書
那些年,我們濫用的字體

TAG:字體排印 | Android開發 | 質感設計MaterialDesign |