iOS UITableViewCell 性能优化

2018-03-31  本文已影响38人  隔壁陈嘉敏

每一个有使用列表 App 都会用到 UITableView 或 UICollectionView,这就意味着也会用到 UITableViewCell 或 UICollectionViewCell。因为 UITableView 和 UICollectionView 不是静止不动的,在与用户交互过程中,需要通过不断地滚动来更新数据,而更新数据的展示就需要通过更新 UITableViewCell 和 UICollectionViewCell 的展示数据。

以 UITableViewCell 为例,UITableViewCell 自带一个UIImageView 和两个 UILabel,但是这些控件的布局是由 UITableViewCellStyle 决定的,使用 setFrame: 也是没有效果。显然只有这三个控件和固定的几种样式,是满足不了大多数产品需求和美工设计的。这个时候,我们就会想到使用复合视图的方式来实现设计需求,即在 UITableViewCell 的基础上添加新的视图控件。

然而,使用复合视图并不是一个好的方案,这就意味着将增加了视图层次结构的嵌套层次。虽然视图层次的多层嵌套是难免的,也是必要的,但是深层次的嵌套结构势必影响性能。因为当父视图更新布局时,就会触发 setNeedsLayout: 方法,而当这个方法被触发时也会触发 layoutSubviews: 方法去更新所有子视图的布局。所以我们应当避免在视图层次结构中多层嵌套,尽量保持扁平化。

那么问题来了,不用复合视图要怎么解决复杂的列表设计呢?
那就在一个视图控件上实现要多个视图控件才能做到的事情。我们使用重写 UIView 的 drawRect: 方法来自定义渲染元素,将需要显示的图片和文字直接绘制到一张视图上。

自定义 UITableViewCell 的头文件 ImproveTableViewCell.h :

/**
 绘制 cell
 */
@interface ImproveTableViewCell : UITableViewCell

/**
 标题
 */
@property (nonatomic, copy) NSString *strTitle;

/**
 图片组
 */
@property (nonatomic, copy) NSArray<NSString *> *arrImage;

/**
 日期
 */
@property (nonatomic, copy) NSString *strDate;

@end

实现文件 ImproveTableViewCell.m :


@implementation ImproveTableViewCell


/**
 重写视图方法绘制

 @param rect 坐标大小
 */
- (void)drawRect:(CGRect)rect {
 
    // 屏幕宽
    CGFloat fScreenWidth = [[UIScreen mainScreen] bounds].size.width;
    // 文本属性
    NSDictionary *dicAttribute;
    
    // 标题
    dicAttribute = @{NSFontAttributeName: [UIFont systemFontOfSize:14], NSForegroundColorAttributeName: [UIColor colorWithWhite:0.2 alpha:1.0]};
    [self.strTitle drawInRect:CGRectMake(10, 10, fScreenWidth - 20, 20) withAttributes:dicAttribute];
    
    // 图片组
    // 图片宽
    CGFloat fImageWidth = (fScreenWidth - 40)/3;
    for (int i = 0; i < 3; i++) {
        
        UIImage *imgPicture = [UIImage imageNamed:self.arrImage[i]];
        [imgPicture drawInRect:CGRectMake(10 + i * (fImageWidth + 10), 40, fImageWidth, fImageWidth * 3/4)];
    }
    
    // 日期
    dicAttribute = @{NSFontAttributeName: [UIFont systemFontOfSize:13], NSForegroundColorAttributeName: [UIColor colorWithWhite:0.6 alpha:1.0]};
    [self.strDate drawInRect:CGRectMake(10, 45 + fImageWidth * 3/4, fScreenWidth - 20, 20) withAttributes:dicAttribute];
    
    // 分割线
    [[UIColor colorWithWhite:0.9 alpha:1.0] set];
    UIRectFill(CGRectMake(0, 65 + fImageWidth * 3/4, fScreenWidth, 5));
}

@end

UITableViewDelegate 和 UITableViewDataSource 的方法实现:

- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
    
    ImproveTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:gDrawID];
    if (cell == nil) {
        
        cell = [[ImproveTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:gDrawID];
        
    }
    cell.strTitle = indexPath.row%2 ? @"蜡笔小新--lol船长" : @"葛力姆乔·贾卡杰克";
    cell.arrImage = indexPath.row%2 ? @[@"test1", @"test2", @"test1"] : @[@"test2", @"test1", @"test2"];
    cell.strDate = indexPath.row%2 ? @"2018-03-30 大傻逼" : @"2018-03-31 小傻逼";
        
    // 更新渲染
    [cell setNeedsDisplay];
    
    return cell;
}

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

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    return ([[UIScreen mainScreen] bounds].size.width - 40)/4 + 70;
}

结果截图:


结果截图@2x.png

参考资料:《高性能 iOS 应用开发》

上一篇下一篇

猜你喜欢

热点阅读