欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

UITableView 优化整理

程序员文章站 2022-06-01 11:29:12
...

UITableView 优化整理

UITableView 优化整理

下面根据这些优化策略来使用代码展示

1: 尽量少的Cell的类型
当Cell的结构基本差不多时候,可以将Cell只创建一种Cell,这样Cell的体积会增大,但是Cell的数量不会有很多,
UITableViewCell的复用机制是离屏就会进入缓存池中,那么一屏可以有N个Cell,那个一种Cell的缓存数就是N+1,如果有M种Cell,那么缓存数就是M*N个.利用同一种类型的cell,去灵活利用view的hidden属性,可以很好的降低Cell的类型数量,不过依照实际需求看.

typedef enum : NSUInteger {
    FriendsterCellTypeNone = -1,//错误码  不存在
    FriendsterCellTypeAll  = 0 ,//default
    FriendsterCellTypeImage,
    FriendsterCellContent,
} FriendsterCellType;

@interface FriendsterTableViewCell : UITableViewCell

@property (nonatomic ,strong)FriendsterModel *model;

//不设置照片 这个先可以不看,后面优化会用到
@property (nonatomic ,strong)FriendsterModel *noImageModel;

@end

2: 提前计算Cell的高度
系统会先调用“tableView:heightForRowAtIndexPath:”获取每个Cell即将显示的高度,从而确定整个UITableView的布局。然后才调用“tableView:cellForRowAtIndexPath”获取每个Cell,我们也是在这里填充、设置Cell的。
在Model中计算并保存Cell的高度

@interface FriendsterModel : NSObject

@property (nonatomic ,strong)NSString *icon_url;
@property (nonatomic , assign)CGRect iconF;
@property (nonatomic ,strong)UIImage *iconImage;
@property (nonatomic ,strong)NSString *content;
@property (nonatomic , assign)CGRect contentF;
@property (nonatomic ,strong)NSString *name;
@property (nonatomic , assign)CGRect nameF;
@property (nonatomic ,strong)NSString *img_url;
@property (nonatomic , assign)CGRect imgF;
@property (nonatomic , assign)CGFloat cellHeight;

@property (nonatomic , assign)FriendsterCellType cellType;
@property (nonatomic , assign)BOOL isAnimation;
+ (instancetype)friendsterWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
//这个方法是返回对应Cell的高度的,可以在数据层计算好每一个Cell的高度,之后直接从缓存中取出来就可以了,因为UITableView的调用之前会先把所有的Cell的高度全部获取一遍,这里就是返回高度的地方,如果在这里大量计算,会延迟TableView的加载
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    FriendsterModel *model = self.dataArray[indexPath.row];;

    return model.cellHeight;
}

3: 缓存展示数据
例子: 内容页有类似于富文本形式的展示类的东西,
可以将富文本在数据层处理好,缓存在数据中,展示的时候直接复制即可,不用在创建NSMutableAttributedString 来组装数据

4: 缓存展示Cell
对于一些简单的,小的View,可以缓存在数据层,用的时候直接拿出来,不用在Cell里面进行重复创建.

5: 对于不透明的View,设置opaque为YES,这样在绘制该View时,就不需要考虑被View覆盖的其他内容(尽量设置Cell的view为opaque,避免GPU对Cell下面的内容也进行绘制).
6: 尽量减少 Cell 的视图层级,可以使用异步绘制的方式,并且少用或不用透明的视图。尽量显示“大小刚好合适的图片资源”
7: 避免离屏渲染,比如同时使用

view.layer.masksToBounds = YES;
 view.layer.cornerRadius = 20.0;

可以用 使用CAShapeLayer和UIBezierPath设置圆角.

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
imageView.image = [UIImage imageNamed:@"3"];
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:imageView.bounds.size];

CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
//设置大小
maskLayer.frame = imageView.bounds;
//设置图形样子
maskLayer.path = maskPath.CGPath;
imageView.layer.mask = maskLayer;
[self.view addSubview:imageView];

8: 快速滑动时按需加载

快滑动过程中,只加载目标范围内的Cell,这样按需加载,极大的提高流畅度。

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{

        NSIndexPath *ip = [self indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)];
    NSIndexPath *cip = [[self indexPathsForVisibleRows] firstObject];
    NSInteger skipCount = 8;
    if (labs(cip.row-ip.row)>skipCount) {
        NSArray *temp = [self indexPathsForRowsInRect:CGRectMake(0, targetContentOffset->y, self.width, self.height)];
        NSMutableArray *arr = [NSMutableArray arrayWithArray:temp];
        if (velocity.y<0) {
            NSIndexPath *indexPath = [temp lastObject];
            if (indexPath.row+33) {
                [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-3 inSection:0]];
                [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-2 inSection:0]];
                [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-1 inSection:0]];
            }
        }
        [needLoadArr addObjectsFromArray:arr];
    }

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ...
        if (needLoadArr.count>0&&[needLoadArr indexOfObject:indexPath]==NSNotFound) {
        [cell clear];
        return;
    }
    ...
 }

9: 图片加载优化:

  • 当用户手动 drag table view 的时候,会加载 cell 中的图片; * 在用户快速滑动的减速过程中,不加载过程中 cell
  • 中的图片(但文字信息还是会被加载,只是减少减速过程中的网络开销和图片加载的开销);
  • 在减速结束后,加载所有可见 cell 的图片(如果需要的话);

/*
    优化达到的效果
 1: 当用户手动 drag table view 的时候,会加载 cell 中的图片;
 2: 在用户快速滑动的减速过程中,不加载过程中 cell 中的图片(但文字信息还是会被加载,只是减少减速过程中的网络开销和图片加载的开销);
 3: 在减速结束后,加载所有可见 cell 的图片(如果需要的话);
 4: 在减速结束后,需要显示的Cell的图片要优先下载.

 scrollViewWillBeginDragging 即将开始拖拽
 scrollViewWillEndDragging: withVelocity: targetContentOffset: 即将停止拖拽
 scrollViewDidEndDecelerating 已经停止减速

 进一步优化
 1: 如果内存中有图片的缓存,减速过程中也会加载该图片
 2: 如果图片属于 targetContentOffset 能看到的 cell,正常加载,这样一来,快速滚动的最后一屏出来的的过程中,用户就能看到目标区域的图片逐渐加载
 */


//即将开始拖动
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    NSLog(@"%s",__func__);
//    _isNeedLoadImage = NO;
}

//即将停止拖动  滚动很快时,只加载目标范围内的Cell,这样按需加载,极大的提高流畅度。
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    NSLog(@"%s",__func__);
    //  先获取当前开始减速时第几行
    NSIndexPath *ip = [self.tableView indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)];

    NSIndexPath *cip = [[self.tableView indexPathsForVisibleRows] firstObject];

    NSLog(@"%@",ip);
    NSLog(@"%@",cip);

    NSInteger skipCount = 6;//判断快速滑动的cell跨越的数量

    if (labs(cip.row-ip.row)>skipCount) {
        _isQuickScroll = YES;
    }else{
        _isQuickScroll = NO;
    }


}
//即将开始减速
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
    NSLog(@"%s",__func__);
    _isDecelerationing = YES;

}


//已经停止减速
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    NSLog(@"%s",__func__);
     _isNeedLoadImage = YES;
    _isDecelerationing = NO;
    _isQuickScroll = NO;
    //刷新当前屏幕可见CEll
    [self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}

完成!!!!

相关标签: uitableview 优化