对于 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