UITableView 優(yōu)化整理

下面根據(jù)這些優(yōu)化策略來使用代碼展示


UITableView滑動優(yōu)化.png

1: 盡量少的Cell的類型

當Cell的結構基本差不多時候,可以將Cell只創(chuàng)建一種Cell,這樣Cell的體積會增大,但是Cell的數(shù)量不會有很多,

UITableViewCell的復用機制是離屏就會進入緩存池中,那么一屏可以有N個Cell,那個一種Cell的緩存數(shù)就是N+1,如果有M種Cell,那么緩存數(shù)就是M*N個.利用同一種類型的cell,去靈活利用view的hidden屬性,可以很好的降低Cell的類型數(shù)量,不過依照實際需求看.

typedefenum: NSUInteger {   
FriendsterCellTypeNone = -1,//錯誤碼  不存在
FriendsterCellTypeAll  =0,//default
FriendsterCellTypeImage,   
FriendsterCellContent,} FriendsterCellType;

@interfaceFriendsterTableViewCell:UITableViewCell

@property(nonatomic,strong)FriendsterModel *model;//不設置照片 這個先可以不看,后面優(yōu)化會用到
@property(nonatomic,strong)FriendsterModel *noImageModel;

@end

2: 提前計算Cell的高度

系統(tǒng)會先調(diào)用“tableView:heightForRowAtIndexPath:”獲取每個Cell即將顯示的高度,從而確定整個UITableView的布局。然后才調(diào)用“tableView:cellForRowAtIndexPath”獲取每個Cell,我們也是在這里填充、設置Cell的。

在Model中計算并保存Cell的高度

@interfaceFriendsterModel:NSObject

@property(nonatomic,strong)NSString*icon_url;

@property(nonatomic,assign)CGRecticonF;

@property(nonatomic,strong)UIImage*iconImage;

@property(nonatomic,strong)NSString*content;

@property(nonatomic,assign)CGRectcontentF;

@property(nonatomic,strong)NSString*name;

@property(nonatomic,assign)CGRectnameF;

@property(nonatomic,strong)NSString*img_url;

@property(nonatomic,assign)CGRectimgF;

@property(nonatomic,assign)CGFloatcellHeight;

@property(nonatomic,assign)FriendsterCellType cellType;

@property(nonatomic,assign)BOOLisAnimation;

+ (instancetype)friendsterWithDict:(NSDictionary*)dict;

- (instancetype)initWithDict:(NSDictionary*)dict;

//這個方法是返回對應Cell的高度的,可以在數(shù)據(jù)層計算好每一個Cell的高度,之后直接從緩存中取出來就可以了,因為UITableView的調(diào)用之前會先把所有的Cell的高度全部獲取一遍,這里就是返回高度的地方,如果在這里大量計算,會延遲TableView的加載

- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{   

FriendsterModel *model =self.dataArray[indexPath.row];

return model.cellHeight;

}

3: 緩存展示數(shù)據(jù)
例子: 內(nèi)容頁有類似于富文本形式的展示類的東西,
可以將富文本在數(shù)據(jù)層處理好,緩存在數(shù)據(jù)中,展示的時候直接復制即可,不用在創(chuàng)建NSMutableAttributedString 來組裝數(shù)據(jù)

4: 緩存展示Cell

對于一些簡單的,小的View,可以緩存在數(shù)據(jù)層,用的時候直接拿出來,不用在Cell里面進行重復創(chuàng)建.

5: 對于不透明的View,設置opaque為YES,這樣在繪制該View時,就不需要考慮被View覆蓋的其他內(nèi)容(盡量設置Cell的view為opaque,避免GPU對Cell下面的內(nèi)容也進行繪制).

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.boundsbyRoundingCorners:UIRectCornerAllCorners cornerRadii:imageView.bounds.size];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];//設置大小
maskLayer.frame= imageView.bounds;//設置圖形樣子
maskLayer.path= maskPath.CGPath;
imageView.layer.mask= maskLayer;
[self.viewaddSubview:imageView];

8: 快速滑動時按需加載

快滑動過程中,只加載目標范圍內(nèi)的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:[NSIndexPathindexPathForRow: indexPath.row-3 inSection: 0]];

                            [arr addObject:[NSIndexPathindexPathForRow: indexPath.row-2 inSection: 0]];

                                [arr addObject:[NSIndexPathindexPathForRow: 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: 圖片加載優(yōu)化:

當用戶手動 drag table view 的時候,會加載 cell 中的圖片; * 在用戶快速滑動的減速過程中,不加載過程中 cell

中的圖片(但文字信息還是會被加載,只是減少減速過程中的網(wǎng)絡開銷和圖片加載的開銷);

在減速結束后,加載所有可見 cell 的圖片(如果需要的話);

/*

優(yōu)化達到的效果

1: 當用戶手動 drag table view 的時候,會加載 cell 中的圖片;

2: 在用戶快速滑動的減速過程中,不加載過程中 cell 中的圖片(但文字信息還是會被加載,只是減少減速過程中的網(wǎng)絡開銷和圖片加載的開銷);

3: 在減速結束后,加載所有可見 cell 的圖片(如果需要的話);

4: 在減速結束后,需要顯示的Cell的圖片要優(yōu)先下載.

scrollViewWillBeginDragging 即將開始拖拽

scrollViewWillEndDragging: withVelocity: targetContentOffset: 即將停止拖拽

scrollViewDidEndDecelerating 已經(jīng)停止減速

進一步優(yōu)化

1: 如果內(nèi)存中有圖片的緩存,減速過程中也會加載該圖片

2: 如果圖片屬于 targetContentOffset 能看到的 cell,正常加載,這樣一來,快速滾動的最后一屏出來的的過程中,用戶就能看到目標區(qū)域的圖片逐漸加載

*/

//即將開始拖動

- (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView{

       NSLog(@"%s",__func__);//   

      _isNeedLoadImage = NO;

}

//即將停止拖動  滾動很快時,只加載目標范圍內(nèi)的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);

      NSIntegerskipCount =6;//判斷快速滑動的cell跨越的數(shù)量

      if(labs(cip.row-ip.row)>skipCount) { 

            _isQuickScroll =YES;   

             }else{

          _isQuickScroll =NO;   

      }
}

//即將開始減速- (void)scrollViewWillBeginDecelerating:(UIScrollView*)scrollView{

      NSLog(@"%s",__func__); 

      _isDecelerationing =YES;

}

//已經(jīng)停止減速

- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView{

NSLog(@"%s",__func__);

      _isNeedLoadImage =YES;

      _isDecelerationing =NO;

      _isQuickScroll =NO;

    //刷新當前屏幕可見CEll

    [self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}

完成!!!!

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容