关于字体适配的那些事
2016-01-18 00:26
381 查看
前言
之前做过很多项目都没考虑过字体适配问题。相信绝大多数人在做项目时,都没仔细去考虑这件事。一般都是根据UI出的图做个估算,有耐心的估计会自己拿工具测量下。如今,考虑到iPhone机型的多样性,UI设计师不可能针对每一款iPhone的屏幕出一套UI图。一般而言,都是基于5s的标准出UI。当我们在设置字体时,往往都是基于UI并且针对不同的屏幕字体也都是绝对的。那么问题来了,细心的同学可能会注意到,相同大小的字体在5s或6上也许差别不大,但在6p上字体有缩小的现象,其原因由分辨率导致。在6出来不久,曾看过有关适配的文章,其中关于iPhone尺寸规格如下:
设备 | 宽 | 高 | 对角线 | 逻辑分辨率 | 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 |
从iPhone5(s)发展到iPhone6(+),由于高宽比保持不变,iOS对图标、图片、字体进行等比放大自适应,清晰度会有所降低。同时,绝对坐标布局会导致在大屏下出现偏左偏上的问题。从分辨率的角度来看,iPhone6沿用二倍图(@2x),但需为iPhone6+提供更高的三倍图(@3x);从屏幕尺寸角度来看,需要重新对UI元素尺寸和布局进行适配,以期视觉协调。
字体适配
以上属于科普类的东西,下面来点实际的。关于字体适配有2种方案。
方案一:
设置一个大小区域范围,比如10~30
pointSize的范围(pointSize为
UIFont的一个CGFloat类型的属性),然后
for循环降序遍历此范围设置一个临时的
UIFont变量,根据此变量计算当前文本的大小,与当前
UILabel的
height作比较找出合适的字体。
#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,那么我们不可避免的要
hook下
UIFont的类方法
`fontWithName:size:做个函数交换的处理。
函数的交换我们需要用到
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创建一个
Categroy文件,文件名为
AdaptiveFont。在实现文件代码如下:
@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若是绝对值,会出现文字显示不全的问题。
在用法上,方法一只需调用
adjustFontSizeToFillItsContents,而方法二需在
application:didFinishLaunchingWithOptions:函数调用下
hook。
当然,这并不是最终也不是最好的适配方案。个人觉得根据
PPI适配字体,限于经历有限只能研究到这。
欢迎纠错,有什么好的字体适配方案也可以在下方评论进行探讨。
Demo地址:https://github.com/keleyundou/AdaptiveFontDemo
相关文章推荐
- Vim基本操作
- MyEclipse中配置maven,入门操作!
- Java Web开发过程中常遇的小问题
- Hibernate使用自定义脚本替换注解或者xml文件中的自动生成表结构
- Hibernate使用自定义脚本替换注解或者xml文件中的自动生成表结构
- Hibernate使用自定义脚本替换注解或者xml文件中的自动生成表结构
- IDEA快捷键汇总
- 创建类
- python抓取京东商品颜色&beautifulsoup的一些常用函数
- 卷积神经网络及其在图像处理中的应用
- JavaScript基础——高级技巧
- Android进阶——git上传代码到coding.net
- python的threading和multiprocessing模块初探
- 干货分享:30 位创业精英的 30 条创业心得
- JS日期加减,日期运算
- 《老码农教你学英语》
- NodeJs对Mysql封装
- 由 python 自定义 class 引发的两个问题
- 使用BeanNameAutoProxyCreator实现spring的自动代理
- 在Python3.4下,用cx_freeze打包PyQt4程序