iOS优化:解决iOS中像素不对齐问题

[这是第1篇]

导语:像素对齐并不是一个复杂的问题,但是开发中稍不注意的话,是会造成像素不对齐的情况(恰恰容易被忽视掉),本文使用一个案例来分析如何解决像素不对齐问题。

背景知识:像素对齐

1、基础
  • iOS设备上,有逻辑像素(point)和 物理像素(pixel)之分,像素对齐指的是物理像素对齐,对齐就是像素点的值是整数,如某视图的宽高是100pixel * 100 pixel。

  • point和pixel的比例是通过[[UIScreen mainScreen] scale]来制定的。在没有视网膜屏之前,1point = 1pixel;但是2x和3x的视网膜屏出来之后,1point等于2pixel或3pixel。

  • 在UI设计师提供的设计稿标注,和在代码中设置frame,其中x,y,width,height的单位是 逻辑像素(point);GPU在渲染图形之前,系统会将逻辑像素(point)换算成 物理像素(pixel)

2、像素对齐 VS 像素不对齐
  • 逻辑像素(point)乘以2(2x的视网膜屏) 或3(3x的视网膜屏)得到整数值,或者说得到的浮点数且小数点后都是0的,这就像素对齐了,否则就是像素不对齐

  • 出现像素不对齐的情况,会导致在GPU渲染时,对没对齐的边缘,需要进行插值计算,这个插值计算的过程会有性能损耗

3、发现像素不对齐
  • 在模拟器上提供了Debug -->Color Misaligned Images选项可以把像素不对齐的部分显示出来;也可以使用Core AnimationDisplay Settings中的Color Misaligned Images选项将像素不对齐的部分显示出来

  • 当UIView(及其子类)的frame像素不对齐显示洋红色;当图片的像素大小与控件的大小不一致而导致需要缩放时,显示黄色

  • 因为项目中大量使用UITableView来构建UI界面【详细参考iOS实录1:使用UITableView构建UI界面】。下面就QSUseTableViewDemo中的详情页来对比优化前后的效果。优化前,开启模拟器上的Debug -->Color Misaligned Images选项,发现:文本部分出现洋红色(frame像素不对齐)和 图片部分是黄色(图片的缩放导致的不对齐)。

优化前.png

一、文本计算的坑

1、存在的问题

理论上设置View的大小,最好预先设置好,尽量不要计算。但是项目中,很多时候需要先计算出文本在某字体下的宽高,再设置view的frame。,有时候文本计算得到的width和height是小数,如16.48、15.32。如果直接使用,必然会造成像素不对齐的问题(因为16.48、15.32乘以2或3得到的都不是整数)。

2、解决办法

我们在项目扩展了NSString方法,使用新增的方法统一计算文本的大小,在这些方法中使用ceil()将小数点后数据除去,使得计算的结果小数点后都是0

//单行的
- (CGSize)textSizeWithFont:(UIFont*)font{

   CGSize textSize = [self sizeWithAttributes:@{NSFontAttributeName:font}];
   textSize = CGSizeMake((int)ceil(textSize.width), (int)ceil(textSize.height));
   return textSize;
}

/**
 根据字体、行数、行间距和constrainedWidth计算多行文本占据的size
 **/
- (CGSize)textSizeWithFont:(UIFont*)font
                numberOfLines:(NSInteger)numberOfLines
                  lineSpacing:(CGFloat)lineSpacing
             constrainedWidth:(CGFloat)constrainedWidth
            isLimitedToLines:(BOOL *)isLimitedToLines{

    if (self.length == 0) {
        return CGSizeZero;
    }
    CGFloat oneLineHeight = font.lineHeight;
    CGSize textSize = [self boundingRectWithSize:CGSizeMake(constrainedWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:font} context:nil].size;

    CGFloat rows = textSize.height / oneLineHeight;
    CGFloat realHeight = oneLineHeight;
    // 0 不限制行数
    if (numberOfLines == 0) {
        if (rows >= 1) {
            realHeight = (rows * oneLineHeight) + (rows - 1) * lineSpacing;
        }
    }else{
        if (rows > numberOfLines) {
            rows = numberOfLines;
            if (isLimitedToLines) {
                *isLimitedToLines = YES;  //被限制
            }
        }
        realHeight = (rows * oneLineHeight) + (rows - 1) * lineSpacing;
    }

    return CGSizeMake(ceil(constrainedWidth),ceil(realHeight));
}

@end

二、UITableview的header和footer高度的坑

1、存在的问题

项目中使用Group Style的UITableview,为了避免让系统去设置header或者footer的高度,我们自己去设置tableView:heightForHeaderInSection: tableView:heightForFooterInSection的值,早前做法是直接将其返回0.01f,达到隐藏header和footer的效果,但是这么做是会造成像素不对齐

2、解决办法

使用尽可能下的数值,0.01还不够小,直接使用系统提供的CGFLOAT_MIN吧。

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    return CGFLOAT_MIN;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return CGFLOAT_MIN;
}

注意:在设置UITableViewCell的高度时候,使用的浮点数,小数点后不可以有0的数,否则造成像素不对齐。

3、解决效果

注明:经过第一和第二步的优化,文本像素不对齐的问题解决了。

文本像素不对齐解决.png

三、图片像素不对齐的情况

1、存在的问题

图片的size和显示图片的imageView的size(逻辑像素(point))不相等。

2、解决办法

图片分为两种,本地图片和网络上下载的图片,前者是UI提供的,存在项目中,这就要求**UI设计师同事提供@2x和@3x图片,因为@2x的图片在@3x的屏幕上也会发生像素不对齐的问题;而网络上获取的图片没有@2x和@3x的区别,需要我们缩放图片到与UIImageView对应的尺寸,且缩放后的图片的scale和[UIScreen mainScreen].scale相等,再显示出来。

1)图片缩放的方法(分类新增UIImage的缩放方法)

- (UIImage *)scaleImageWithSize:(CGSize)size{

    if (CGSizeEqualToSize(size, self.size)) {
        return self;
    }

    //创建上下文
    UIGraphicsBeginImageContextWithOptions(size, YES, [UIScreen mainScreen].scale);

    //绘图
    [self drawInRect:CGRectMake(0, 0, size.width, size.height)];

    //获取新图片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();  
   return newImage;
}

2)图片缩放在非主线程,更新图片在主线程

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //压缩背景图片 & 头像图片
        UIImage *bgImage = [[UIImage imageNamed:self.cellModel.bgImageName] scaleImageWithSize:_bgImageView.frame.size];
        UIImage *image = [[UIImage imageNamed:self.cellModel.iconImageName] scaleImageWithSize:_iconImageView.frame.size];
        dispatch_sync(dispatch_get_main_queue(), ^{
            _bgImageView.image = bgImage;
            _iconImageView.image = image;
            _iconImageView.hidden = (image != nil) ? NO : YES;
        });
    });

注明:图片的缩放是相对耗时的,不应该放在UI线程(主线程),否则影响UI的流程体验;这里使用加载本地图片,模拟从网络获取图片。一般项目中使用SDWebImage来下载网络图片,为了更好处理图片的缩放和圆角等问题,需要在原来库增加某些特性(图片缩放、裁圆角和缓存等),这个后面再说。

3、解决效果

经过第三步的优化,图片不对齐的问题(黄色区域没有了)被解决。

图片像素不对齐解决.png

总结:解决像素不对齐的基本准则

1、frame设置时候,使用整数; 需要计算frame时候,计算的结果使用ceil处理一下,避免小数点后有非0数存在。UITableViewCell的高度的高度是整数。
2、项目中,要求UI设计师提供@2x和@3x的切图。
3、设置imageView的size要和切图的size(逻辑像素(point))相等。
4、网络上获取的图片的size要缩放和imageView的size(逻辑像素(point))要相等,缩放后的图片的scale和[UIScreen mainScreen].scale要相等。解决方案参考iOS实录17:网络图片的优化显示
5、缩放这样的耗时操作应该放到子线程去做。最好做缓存,避免每次显示都需要缩放操作。

源代码直通车QSUseTableViewDemo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容