摘要:對于開發同學來說不管用戶比例多高設計稿都按給絕對是最值得吐槽的事情之一在我剛開始接觸開發的那個階段每當有人問起這件事我都說的做法就是看著差不多就行了后來有些要求特別高的設計開發同學就只能很苦逼的一個一個的改到滿意為止我看現在不少輔助開發工具
對于 Android 開發同學來說, "不管用戶比例多高, 設計稿都按 iOS 給"絕對是最值得吐槽的事情之一.
在我剛開始接觸 Android 開發的那個階段, 每當有人問起這件事, 我都說 "Android 的做法就是看著差不多就行了..." 后來有些要求特別高的設計, Android 開發同學就只能很苦逼的一個 dp 一個 dp 的改到 UI 滿意為止. 我看現在不少輔助開發工具的思路也是這樣.
17 年底 ~ 18 年初搞 UI 大改版的時候, iOS 開發同學 傳人 Joe 跟設計敲定了 iOS 的還原方式. 我覺得如果 Android 不搞的話之后開發就太煩了, 就決定 試一試. 最后的方案雖然不是特別通用, 但也能解決大部分問題.
然后就被設計小姐姐催著寫原理, 然后一年就過去了...
從這里開始
上圖中, 粉底的 "22 一行"和 "22 多行"是設計小姐姐給的參照圖, 是用 Sketch 輸出的, 使用 22 號字+默認行高情況下的設計稿上的樣子. 綠底和黃底的 "22 一行"是 Nexus 5 上, 使用 22dp 的樣子; 藍底(疊加顯示成紫色)的 "22 四行"也是 22dp, 文字用 " " 換行. 底色之間的差異就是"行高"的差異.
可見綠底一行的行高有一點細微的偏差, 黃底一行因為疊加了 4 次這個誤差, 比較明顯. 多行情況下的誤差更大, 因為 Android 和 iOS 在多行文本排版的概念上差異很大. 參照圖上單行和多行是能對上的, 現在我們要想辦法讓 Android 的單行和多行都能跟參照圖對上.
單行對齊
觀察發現單行差的是底部的一段空白, 我稱之為 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 來確定單行和多行的行高關系:
觀察發現: 兩行文字的高度 = 單行文字的高度 + 單行文字設置 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, 真是幸運.
帶行高的對齊:
局限性
只關注行高, 不關注文本寬度, 所以換行還是跟 iOS 不一樣.
并不是對所有的字號/字體都有效, 只處理了我們常用的字號(其它字號要加也不難), 默認字體.
沒有抽成庫, 原因就是上面那條.
18 年 Android 最新的 support 庫好像為 AppCompatTextView 增加了行高支持, 但我還沒有來得及試.
其它已知問題
5.0 以下系統需要特殊處理 paddingBottom, 因為會增加額外的 lineSpaceExtra
但是有些 5.0 及以上的手機 (vivo X9, 錘子) 居然也有這個問題, 管不了了...
因為直接修改了 TextView 的 paddingTop 和 paddingBottom, 如果設計稿上有上下邊距, 只能用 margin 或者再嵌套一層的方式解決.
也許可以寫得更完善些.
在生產環境中使用時, 有同學發現該 TextView 中 ClickableSpan 的點擊事件無法被觸發.
還木有解決...
@Uraka.Lee
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/7064.html
閱讀 713·2023-04-25 19:43
閱讀 3910·2021-11-30 14:52
閱讀 3785·2021-11-30 14:52
閱讀 3852·2021-11-29 11:00
閱讀 3783·2021-11-29 11:00
閱讀 3869·2021-11-29 11:00
閱讀 3558·2021-11-29 11:00
閱讀 6105·2021-11-29 11:00