關于字體適配的那些事

前言

之前做過很多項目都沒考慮過字體適配問題。相信絕大多數(shù)人在做項目時录淡,都沒仔細去考慮這件事捌木。一般都是根據(jù)UI出的圖做個估算,有耐心的估計會自己拿工具測量下嫉戚。如今刨裆,考慮到iPhone機型的多樣性,UI設計師不可能針對每一款iPhone的屏幕出一套UI圖彬檀。一般而言帆啃,都是基于5s的標準出UI。當我們在設置字體時窍帝,往往都是基于UI并且針對不同的屏幕字體也都是絕對的努潘。那么問題來了,細心的同學可能會注意到坤学,相同大小的字體在5s或6上也許差別不大疯坤,但在6p上字體有縮小的現(xiàn)象,其原因由分辨率導致深浮。
在6出來不久压怠,曾看過有關適配的文章,其中關于iPhone尺寸規(guī)格如下:

設備 對角線 邏輯分辨率 scale Factor 設備分辨率 PPI
3GS 2.4inch 4.5inch 3.5inch 320x480 @1x 320x480 163
4(s) 2.31inch 4.5inch 3.5inch 320x480 @2x 640x960 326
5c 2.33inch 4.90inch 4inch 320x568 @2x 640x1136 326
5(s) 2.31inch 4.87inch 4inch 320x568 @2x 640x1136 326
6 2.64inch 5.44inch 4.7inch 375x667 @2x 750x1334 326
6p 3.06inch 6.22inch 5.5inch 414x736 @3x 1242x2208 401

從iPhone3GS/iPhone4(s)過渡到iPhone5(s)時飞苇,在邏輯上寬度不變高度稍高刑峡,之前舊的素材和布局通過AutoresizingFlexible簡單適配即可運行得很好,但由于高寬比增大玄柠,上下兩端出現(xiàn)黑粗邊(典型如LaunchImage)突梦。從分辨率的角度來看,除了需要提供LaunchImage這種滿屏圖羽利,其他基本沿用二倍圖(@2x)宫患;從屏幕尺寸角度來看,需要對縱向排版略加調整这弧。
從iPhone5(s)發(fā)展到iPhone6(+)娃闲,由于高寬比保持不變虚汛,iOS對圖標、圖片皇帮、字體進行等比放大自適應卷哩,清晰度會有所降低。同時属拾,絕對坐標布局會導致在大屏下出現(xiàn)偏左偏上的問題将谊。從分辨率的角度來看,iPhone6沿用二倍圖(@2x)渐白,但需為iPhone6+提供更高的三倍圖(@3x)尊浓;從屏幕尺寸角度來看,需要重新對UI元素尺寸和布局進行適配纯衍,以期視覺協(xié)調栋齿。

字體適配

以上屬于科普類的東西,下面來點實際的襟诸。

關于字體適配有2種方案瓦堵。

  • 方案一:
    設置一個大小區(qū)域范圍,比如10~30pointSize的范圍(pointSize為UIFont的一個CGFloat類型的屬性)歌亲,然后for循環(huán)降序遍歷此范圍設置一個臨時的UIFont變量谷丸,根據(jù)此變量計算當前文本的大小,與當前UILabelheight作比較找出合適的字體应结。

#define ADAPTIVE__FONT_SIZE_MINIMUM_VALUE 20
#define ADAPTIVE_FONT_SIZE_MAXIMUM_VALUE 30

-(UIFont *) adjustFontSizeToFillItsContents
{
    NSString* text = self.text;
    
    for (int i = ADAPTIVE_FONT_SIZE_MAXIMUM_VALUE; i>ADAPTIVE__FONT_SIZE_MINIMUM_VALUE; i--) {
        
        UIFont *font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
        NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];
        
        CGRect rectSize = [attributedText boundingRectWithSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil];
        
        if (rectSize.size.height <= self.frame.size.height) {
            return [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
            break;
        }
    }
    return self.font;
}

  • 方案二:
    計算出一個scale重新設置UIFont各淀,偽代碼如下:
CGFloat scale = ([UIScreen mainScreen].bounds.size.width / 320);
NSLog(@"before : %.1f", [font pointSize]);
font = [UIFont fontWithName:[font fontName] size:fontSize * scale];
NSLog(@"after : %.1f", [font pointSize]);

既然需要重新設置UIFont叉存,那么我們不可避免的要hookUIFont的類方法``fontWithName:size:做個函數(shù)交換的處理。 函數(shù)的交換我們需要用到runtime`機制。

void bd_exchageClassMethod(Class aClass, SEL oldSEL, SEL newSEL)
{
    Method oldClsMethod = class_getClassMethod(aClass, oldSEL);
    assert(oldClsMethod);
    Method newClsMethod = class_getClassMethod(aClass, newSEL);
    assert(newClsMethod);
    method_exchangeImplementations(oldClsMethod, newClsMethod);
}

然后妓局,我們給UIFont創(chuàng)建一個Categroy文件循集,文件名為AdaptiveFont蔗怠。在實現(xiàn)文件代碼如下:

@implementation UIFont (AdaptiveFont)

+ (void)hook
{
    bd_exchageClassMethod([UIFont class], @selector(fontWithName:size:), @selector(hook_fontWithName:size:));
}

+ (UIFont *)hook_fontWithName:(NSString *)fontName size:(CGFloat)fontSize
{
    NSLog(@"before : %.1f", fontSize);
    CGFloat scale = ([UIScreen mainScreen].bounds.size.width / 320);
    NSLog(@"scale : %f", scale);
    UIFont *font = [self hook_fontWithName:fontName size:fontSize * scale];
    NSLog(@"after : %.1f", [font pointSize]);
    printf("<--------------------->\n");
    return font;
}

@end

接口文件暴漏相關方法如下:

@interface UIFont (AdaptiveFont)

+ (void)hook;
+ (UIFont *)hook_fontWithName:(NSString *)fontName size:(CGFloat)fontSize;

@end

相對比較而言厢拭,我還是傾向于方法二。方法一的前提條件是height要適配好玷坠,不能是絕對值蜗搔,否效果。當然八堡,方法二也一樣樟凄,只不過height若是絕對值,會出現(xiàn)文字顯示不全的問題兄渺。
在用法上缝龄,方法一只需調用adjustFontSizeToFillItsContents,而方法二需在application:didFinishLaunchingWithOptions:函數(shù)調用下hook

當然叔壤,這并不是最終也不是最好的適配方案瞎饲。個人覺得根據(jù)PPI適配字體,限于經(jīng)歷有限只能研究到這炼绘。
歡迎糾錯嗅战,有什么好的字體適配方案也可以在下方評論進行探討。

Demo地址:https://github.com/keleyundou/AdaptiveFontDemo

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末俺亮,一起剝皮案震驚了整個濱河市驮捍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铅辞,老刑警劉巖厌漂,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萨醒,死亡現(xiàn)場離奇詭異斟珊,居然都是意外死亡,警方通過查閱死者的電腦和手機富纸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門囤踩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晓褪,你說我怎么就攤上這事堵漱。” “怎么了涣仿?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵勤庐,是天一觀的道長。 經(jīng)常有香客問我好港,道長愉镰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任钧汹,我火速辦了婚禮丈探,結果婚禮上,老公的妹妹穿的比我還像新娘拔莱。我一直安慰自己碗降,他們只是感情好,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布塘秦。 她就那樣靜靜地躺著讼渊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪尊剔。 梳的紋絲不亂的頭發(fā)上精偿,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機與錄音,去河邊找鬼笔咽。 笑死搔预,一個胖子當著我的面吹牛,可吹牛的內容都是我干的叶组。 我是一名探鬼主播拯田,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼甩十!你這毒婦竟也來了船庇?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤侣监,失蹤者是張志新(化名)和其女友劉穎鸭轮,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體橄霉,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡窃爷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了姓蜂。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片按厘。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖钱慢,靈堂內的尸體忽然破棺而出逮京,到底是詐尸還是另有隱情,我是刑警寧澤束莫,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布懒棉,位于F島的核電站,受9級特大地震影響览绿,放射性物質發(fā)生泄漏策严。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一挟裂、第九天 我趴在偏房一處隱蔽的房頂上張望享钞。 院中可真熱鬧,春花似錦诀蓉、人聲如沸栗竖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狐肢。三九已至,卻和暖如春沥曹,著一層夾襖步出監(jiān)牢的瞬間份名,已是汗流浹背碟联。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留僵腺,地道東北人鲤孵。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像辰如,于是被迫代替她去往敵國和親普监。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內容