最近準(zhǔn)備給 VirtualView-iOS 的文本元素新增一個 lineHeight 屬性,以便和 VirtualView-Android配合時能更精確的保證雙平臺的一致性突照。面向 Google 以及 Stack Overflow 編程了一會后發(fā)現(xiàn)帮非,能查到的資料大部分是介紹如何實現(xiàn) lineSpacing 屬性,而不是 lineHeight讹蘑。但是我就是因為 iOS 和 Android 的默認(rèn) lineSpacing 不一致所以才想實現(xiàn)個 lineHeight 澳┛!還是需要自己動手豐衣足食座慰,順帶整理成文章造福后人陨舱。
關(guān)于行間距 lineSpacing
先貼出一張 iOS 中 UILabel 的默認(rèn)排版樣式:
大家也都能看出來,默認(rèn)的排版樣式中版仔,文本的行間距很小游盲,顯得文本十分?jǐn)D。
這種時候蛮粮,設(shè)計師就會提出行間距的需求益缎,希望讓文本展示得更美觀。類似的標(biāo)注就會像這樣:
通常來說既然設(shè)計師要求的是行間距蝉揍,那么我們直接設(shè)置 lineSpacing 就好。但是 UILabel 是沒有這么一個直接暴露的屬性的畦娄,想要修改 lineSpacing又沾,我們需要借助 NSAttributedString 來實現(xiàn)弊仪,示意代碼:
運行一下觀察效果:
雖然用我們的眼睛看上去好像沒什么問題,但是設(shè)計師的火眼金睛一下就能看出來杖刷,和設(shè)計稿要求的有差距:
怎么會成這樣@?這跟說好的不一樣對不對;肌役听?不要慌,我來細(xì)細(xì)解釋下表窘。
正確的實現(xiàn)行間距
先看示意圖:
紅色區(qū)域是默認(rèn)繪制單行文本會占用的區(qū)域典予,可以看到文字的上下是有一些留白的(藍(lán)色和紅色重疊的部分)。設(shè)計師是想要藍(lán)色區(qū)域高度為 10pt乐严,而我們直接設(shè)置 lineSpacing 會將兩行紅色區(qū)域中間的綠色區(qū)域高度設(shè)置為 10pt瘤袖,這就是問題的根源了。
那么這個紅色的區(qū)域高度是多少呢昂验?答案是 label.font.lineHeight
捂敌,它是使用指定字體繪制單行文本的原始行高。
知道了原因后問題就好解決了既琴,我們需要在設(shè)置 lineSpacing 時占婉,減去這個系統(tǒng)的自帶邊距:
觀察一下效果,完美契合:
關(guān)于行高 lineHeight
如果你只關(guān)心 iOS 設(shè)備上的文本展示效果甫恩,那么看到這里就已經(jīng)夠了逆济。但是我需要的是 iOS 和 Android 展現(xiàn)出一模一樣的效果,所以光有行間距是不能滿足需求的填物。主要的原因在前言也提到了纹腌,Android 設(shè)備上的文字上下默認(rèn)留白(上一節(jié)圖中藍(lán)色和紅色重疊的部分)和 iOS 設(shè)備上的是不一致的:
左側(cè)是 iOS 設(shè)備,右側(cè) Android 設(shè)備滞磺,可以看到同樣是顯示 20 號的字體升薯,安卓的行高會偏高一些。在不同的 Android 設(shè)備上使用的字體不一樣击困,可能還會出現(xiàn)更多的差別涎劈。如果不想辦法抹平這差別,就不能真正意義上實現(xiàn)雙端一致了阅茶。
這時候我們可以通過設(shè)置 lineHeight 來使得每一行文本的高度一致蛛枚,lineHeight 設(shè)置為 30pt 的情況下,一行文本高度一定是 30pt脸哀,兩行文本高度一定是 60pt蹦浦。雖然文字的渲染上會有細(xì)微的差別,但是布局上的差別將被完全的抹除撞蜂。lineHeight 同樣可以借助 NSAttributedString 來實現(xiàn)盲镶,示意代碼:
運行一下觀察效果:
在 debug 模式下確認(rèn)了下文本的高度的確正確的侥袜,但是為什么文字都顯示在了行底呢?
修正行高增加后文字的位置
修正文字在行中展示的位置溉贿,我們可以用 baselineOffset 屬性來搞定枫吧。這個屬性十分有用,在實現(xiàn)上標(biāo)下標(biāo)之類的需求時也經(jīng)常用到它宇色。經(jīng)過調(diào)試九杂,發(fā)現(xiàn)最合適的值是 (lineHeight - label.font.lineHeight) / 4
(尚未搞清楚為什么是除以 4 而不是除以 2,希望知道的老司機(jī)指點一二)宣蠕。最終的代碼示例如下:
貼一下在不同字號和行高下的展示效果:
行高和行間距同時使用時的一個問題
不得不說行高和行間距我們都已經(jīng)可以完美的實現(xiàn)了例隆,但是我在嘗試同時使用它們時,發(fā)現(xiàn)了 iOS 的一個 bug(當(dāng)然也可能是一個 feature植影,畢竟不 crash 都不一定是 bug):
著色的區(qū)域都是文本的繪制區(qū)域裳擎,其中看上去是橙色的區(qū)域是 lineSpacing,綠色的區(qū)域是 lineHeight思币。但是為什么單行的文本系統(tǒng)也要展示一個 lineSpacing 奥瓜臁!谷饿?坑爹呢這是;涛摇?
好在我們通常是行高和行間距針對不同的需求分別獨立使用的博投,它們在分開使用時不會觸發(fā)這個問題绸贡。所以在 VirtualView-iOS 庫中,我暫且將高度計算的邏輯保持和系統(tǒng)一致了毅哗。
總結(jié)
至此听怕,成功的為 VirtualView-iOS 添加了對 lineHeight 屬性的支持,更多的實現(xiàn)細(xì)節(jié)大家可以到開源庫中直接看源代碼虑绵。希望我們的 Tangram 方案可以更加完善尿瞭,幫助更多的人一次開發(fā)兩端同時使用,用一塊七巧板拼出大千世界翅睛。