tableView 流畅度优化——Core Animation

debug.png

Color Blended layers
标示混合的图层会为红色,不透明的图层为绿色,通常我们希望绿色的区域越多越好。
Color Hits Green and Misses Red
假如我们设置viewlayer的shouldRasterize为YES,那些成功被缓存的layer会标注为绿色,反之为红色。
Color offscreen-rendered yellow
(offscreen-render)标示哪些layer需要做离屏渲染,黄色的区域就是离屏渲染的地方。

1、Color Blended layers像素混合

现象: UILabel、UIImageView通过设置Cell的背景颜色(默认为nil,也不能设置背景色为clearColor )+ maskTobunds = YES 两者都具备可以消除像素混合,UIButton我怎么试都不能,始终显示红色。

    cell.name.backgroundColor = [UIColor whiteColor];
//    cell.name.layer.masksToBounds = YES;


    cell.sign.backgroundColor = [UIColor whiteColor];
    cell.sign.layer.masksToBounds = YES;

//    cell.place.backgroundColor = [UIColor whiteColor];
    cell.place.layer.masksToBounds = YES;

    
    cell.imageView1.backgroundColor = [UIColor redColor];
    cell.imageView1.layer.masksToBounds = YES;


    cell.imageView2.backgroundColor = [UIColor clearColor];
    cell.imageView2.layer.masksToBounds = YES;

    [cell.btn setBackgroundColor:[UIColor whiteColor]];
    cell.btn.layer.masksToBounds = YES;
    cell.btn.opaque = YES;
Color Blended layers

2、Color offscreen-rendered yellow

shouldRasterize(光栅化)、阴影(需要设置透明度shadowOpacity,单纯的设置layer.opacity 不会)、圆角 都会造成离屏渲染,但iOS 9.0 而UIImageView里png图片设置圆角(不能设置imageView背景色或者为clearColor)不会触发离屏渲染了。

     // 圆角 (当圆角大于t控件最短边的一半会变成黄色,小于等于最短边的一半则为绿色)
    cell.btn.layer.cornerRadius = 25;
    //    cell.btn.layer.cornerRadius = 20;
    cell.btn.layer.masksToBounds = YES;
    
    // 图片在设置圆角下 背景色对离屏渲染的影响
    cell.imageView1.backgroundColor = [UIColor whiteColor];
    cell.imageView1.layer.cornerRadius = 30;
    cell.imageView2.backgroundColor = [UIColor clearColor];


    
    //阴影(需要设置透明度shadowOpacity,单纯的设置layer.opacity也不会)
    cell.name.layer.opacity = 0.5;

    cell.sign.layer.shadowOffset = CGSizeMake(0, 2);
    cell.sign.layer.shadowOpacity = 0.5;
    
    cell.place.layer.shadowOffset = CGSizeMake(0, 2);

为什么是圆角的离屏渲染显示绿色的不是黄色的,我也不清楚,测试中我发现将圆角变大,大于控件最短边长的一半就会变成黄色。(绿色可能表示有缓存可用?)


image.png

3、Color Hits Green and Misses Red

//阴影性能优化
    cell.sign.layer.shadowPath = [UIBezierPath  bezierPathWithRect:cell.sign.bounds].CGPath;
//
//使用光栅化进行优化
    cell.layer.shouldRasterize = YES;
    cell.layer.rasterizationScale = [UIScreen mainScreen].scale;

对阴影可以设置shadowPath来解决,圆角可以通过:使用CAShapeLayer和UIBezierPath设置圆角
也可以用光栅化解决,虽然被Rasterize的图层也会引起离屏渲染,如下图所示,整个cell都被标示为黄色。

layer设置shouldRasterize=YES之后,会把被光栅化的图层保存成位图并缓存起来,其中圆角或者阴影之类的效果也是直接保存到位图当中,当需要渲染到屏幕上的时候只需要到缓存中去取对应的位图进行显示就行了,加快了整个渲染过程。可以通过勾选instruments core animation中的Color Hits Green and Misses Red选项来查看图层是否被缓存了,如果图层显示为绿色则表示已经被缓存起来了,也就是这个缓冲区的内容被复用了,不用在去重新创建缓冲区,反之则是用红色标示。如下图可以看到设置shouldRasterize之后,cell都被标示为绿色了,如果滑动过程中发现都是红色的证明就有问题了。

(全屏为绿色的截屏后没有颜色了,自己想象一下第二张图片都是绿色的吧,手机放在那还会绿色红色 的闪动)


Color Hits Green and Misses Red

适用于内容基本不变的图层

  • 假如图层的内容经常变化,比如cell里面有涉及到动画之类的,那么缓存的内容就无效了,GPU需要重新创建缓存区,导致离屏渲染,这又涉及到OpenGL的上下文环境切换,反而降低性能。
  • 不要过度使用
    缓存区的大小被设置为屏幕大小的2.5倍,假如过分使用同样会导致大量的离屏渲染。
  • 如果缓存的内容超过100ms没有被使用则会被回收。

demo源码:

#import <UIKit/UIKit.h>

@interface CustomCell : UITableViewCell

@property (strong, nonatomic)  UILabel *name;
@property (strong, nonatomic)  UILabel *sign;
@property (strong, nonatomic)  UILabel *place;
@property (strong, nonatomic)  UIImageView *imageView2;
@property (strong, nonatomic)  UIImageView *imageView1;
@property (strong, nonatomic)  UIButton *btn;

@end

#import "CustomCell.h"

@implementation CustomCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self.contentView addSubview:self.imageView1];
        [self.contentView addSubview:self.imageView2];
        [self.contentView addSubview:self.name];
        [self.contentView addSubview:self.sign];
        [self.contentView addSubview:self.place];
        [self.contentView addSubview:self.btn];
        
    }
    return self;
}

-(UIImageView *)imageView1 {
    if (!_imageView1) {
        _imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(12, 12, 56, 56)];
        _imageView1.layer.cornerRadius = 28;
        _imageView1.layer.masksToBounds = YES;
        _imageView1.image = [UIImage imageNamed:@"1"];
    }
    return _imageView1;
}

-(UIImageView *)imageView2 {
    if (!_imageView2) {
        _imageView2 = [[UIImageView alloc] initWithFrame:CGRectMake(80, 12, 56, 56)];
        _imageView2.layer.cornerRadius = 28;
        _imageView2.layer.masksToBounds = YES;
        _imageView2.image = [UIImage imageNamed:@"2"];
    }
    return _imageView2;
}
- (UILabel *)name {
    if (!_name) {
        _name = [[UILabel alloc] initWithFrame:CGRectMake(150, 0, 100, 20)];
        _name.text = @"倚楼听风雨";
    }
    return _name;
}
- (UILabel *)sign {
    if (!_sign) {
        _sign = [[UILabel alloc] initWithFrame:CGRectMake(150, 30, 170, 20)];
        _sign.text = @"宠辱不惊,看云卷云舒";
    }
    return _sign;
}
- (UILabel *)place {
    if (!_place) {
        _place = [[UILabel alloc] initWithFrame:CGRectMake(150, 60, 100, 20)];
        _place.text = @"杭州";
    }
    return _place;
}
- (UIButton *)btn {
    if (!_btn) {
        _btn = [UIButton buttonWithType:UIButtonTypeCustom];
        _btn.frame = CGRectMake(330, 20, 60, 40);
        [_btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
        [_btn setTitle:@"按妞" forState:UIControlStateNormal];
        _btn.layer.borderWidth = 1.0;
        _btn.layer.borderColor = [UIColor blueColor].CGColor;
    }
    return _btn;
}
@end


#import "ViewController.h"
#import "CustomCell.h"

@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>

@property (strong, nonatomic) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.tableView];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark -- Table Delegate

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 100;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CustomCellIdentifier = @"CustomCellIdentifier";
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
    if (cell == nil) {
        cell = [[CustomCell alloc]
                initWithStyle:UITableViewCellStyleDefault
                reuseIdentifier:CustomCellIdentifier];
    }
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 80.0;
}

- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
        _tableView.delegate =self;
        _tableView.dataSource = self;
    }
    return _tableView;
}
@end

参考:iOS app性能优化的那些事(二)

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