美文网首页专注iOS开发优化专题iOS技术交流
iOS优化:解决iOS中像素不对齐问题

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

作者: 南华coder | 来源:发表于2017-05-08 17:23 被阅读1345次

    [这是第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

    相关文章

      网友评论

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

      本文链接:https://www.haomeiwen.com/subject/kyfstxtx.html