對於 Android 開發同窗來講, "無論用戶比例多高, 設計稿都按 iOS 給"絕對是最值得吐槽的事情之一.android
在我剛開始接觸 Android 開發的那個階段, 每當有人問起這件事, 我都說 "Android 的作法就是看着差很少就好了..." 後來有些要求特別高的設計, Android 開發同窗就只能很苦逼的一個 dp 一個 dp 的改到 UI 滿意爲止. 我看如今很多輔助開發工具的思路也是這樣.git
17 年末 ~ 18 年初搞 UI 大改版的時候, iOS 開發同窗 傳人 Joe 跟設計敲定了 iOS 的還原方式. 我以爲若是 Android 不搞的話以後開發就太煩了, 就決定 試一試. 最後的方案雖然不是特別通用, 但也能解決大部分問題.github
而後就被設計小姐姐催着寫原理, 而後一年就過去了...bash
上圖中, 粉底的 "22 一行"和 "22 多行"是設計小姐姐給的參照圖, 是用 Sketch 輸出的, 使用 22 號字+默認行高狀況下的設計稿上的樣子. 綠底和黃底的 "22 一行"是 Nexus 5 上, 使用 22dp 的樣子; 藍底(疊加顯示成紫色)的 "22 四行"也是 22dp, 文字用 "\n" 換行. 底色之間的差別就是"行高"的差別.工具
可見綠底一行的行高有一點細微的誤差, 黃底一行由於疊加了 4 次這個偏差, 比較明顯. 多行狀況下的偏差更大, 由於 Android 和 iOS 在多行文本排版的概念上差別很大. 參照圖上單行和多行是能對上的, 如今咱們要想辦法讓 Android 的單行和多行都能跟參照圖對上.post
觀察發現單行差的是底部的一段空白, 我稱之爲 additionalPaddingBottom
. 對比各類字號的狀況, 發現並無規律, 所以搞出來一組經驗值.開發工具
這個經驗值在 3 倍屏上仍是比較準確的(最重要的是設計走查就用 3 倍屏...), 單行文字位置和行高都能對上. 在其餘倍數的屏幕上基本 ok, 但也有一些異常. 好比在 1.5 倍屏上, 部分字號只能達成行高對的上但文字位置對不上的效果, 並且還受到 setSingleLine
的影響, 15dp + setSingleLine(true)
時誤差尤爲大.字體
/**
* density 爲 3 時的經驗值, 做爲計算 additionalLineSpace 的基數
*/
static {
paddingBottomMap.put(10, 1f / 3);
paddingBottomMap.put(11, 4f / 3);
paddingBottomMap.put(12, 2f / 3);
paddingBottomMap.put(13, 1f / 3);
paddingBottomMap.put(14, 3f / 3);
paddingBottomMap.put(15, 2f / 3);
paddingBottomMap.put(16, 1f / 3);
paddingBottomMap.put(17, 4f / 3);
paddingBottomMap.put(19, 1f / 3);
paddingBottomMap.put(22, 2f / 3);
paddingBottomMap.put(30, 5f / 3);
}
複製代碼
根據 Android 文本排版概念, 我寫了個簡單的 MetricsTextView
來肯定單行和多行的行高關係:spa
觀察發現: 兩行文字的高度 = 單行文字的高度 + 單行文字設置 setIncludeFontPadding(false)
的高度設計
同時, 兩行文字和兩組單行的差異在於文字之間的空白, 所以須要增長 lineSpaceExtra
= topSpace
+ bottomSpace
+ additionalPaddingBottom
. 這樣 Android 也實現了 n 行文字行高 = n x 單行文字行高, 多行也就對上了.
上面都是參考圖使用默認行高的狀況, 若是行高變了呢? 抱歉仍是得基於經驗值.
/**
* sketch 中字號對應的默認行高 (dp)
*/
static {
defaultLineHeightMap.put(10, 14);
defaultLineHeightMap.put(11, 16);
defaultLineHeightMap.put(12, 17);
defaultLineHeightMap.put(13, 18);
defaultLineHeightMap.put(14, 20);
defaultLineHeightMap.put(15, 21);
defaultLineHeightMap.put(16, 22);
defaultLineHeightMap.put(17, 24);
defaultLineHeightMap.put(19, 26);
defaultLineHeightMap.put(30, 42);
}
複製代碼
首先咱們有默認行高的值, 而後把 deltaPaddingTop
= deltaPaddingBottom
= (lineHeight
- defaultLineHeight
) / 2 用 paddingTop 和 paddingBottom 加到 每一行 上 - 實驗結果代表上下加的同樣多, 能夠除 2, 真是幸運.
帶行高的對齊:
paddingBottom
, 由於會增長額外的 lineSpaceExtra
@Uraka.Lee