UITableView筆記整理

tableView性能優(yōu)化 - cell的循環(huán)利用方式1

/**
 *  什么時候調(diào)用:每當(dāng)有一個cell進(jìn)入視野范圍內(nèi)就會調(diào)用
 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 0.重用標(biāo)識
    // 被static修飾的局部變量:只會初始化一次,在整個程序運(yùn)行過程中,只有一份內(nèi)存
    static NSString *ID = @"cell";

    // 1.先根據(jù)cell的標(biāo)識去緩存池中查找可循環(huán)利用的cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    // 2.如果cell為nil(緩存池找不到對應(yīng)的cell)
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }

    // 3.覆蓋數(shù)據(jù)
    cell.textLabel.text = [NSString stringWithFormat:@"testdata - %zd", indexPath.row];

    return cell;
}

tableView性能優(yōu)化 - cell的循環(huán)利用方式2

  • 定義一個全局變量
// 定義重用標(biāo)識
NSString *ID = @"cell";
  • 注冊某個標(biāo)識對應(yīng)的cell類型
// 在這個方法中注冊cell
- (void)viewDidLoad {
    [super viewDidLoad];

    // 注冊某個標(biāo)識對應(yīng)的cell類型
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:ID];
}
  • 在數(shù)據(jù)源方法中返回cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1.去緩存池中查找cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    // 2.覆蓋數(shù)據(jù)
    cell.textLabel.text = [NSString stringWithFormat:@"testdata - %zd", indexPath.row];

    return cell;
}

tableView性能優(yōu)化 - cell的循環(huán)利用方式3

  • 在storyboard中設(shè)置UITableView的Dynamic Prototypes Cell

  • 設(shè)置cell的重用標(biāo)識

  • 在代碼中利用重用標(biāo)識獲取cell

// 0.重用標(biāo)識
// 被static修飾的局部變量:只會初始化一次,在整個程序運(yùn)行過程中,只有一份內(nèi)存
static NSString *ID = @"cell";

// 1.先根據(jù)cell的標(biāo)識去緩存池中查找可循環(huán)利用的cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

// 2.覆蓋數(shù)據(jù)
cell.textLabel.text = [NSString stringWithFormat:@"cell - %zd", indexPath.row];

return cell;

UITableView的常見設(shè)置

// 分割線顏色
self.tableView.separatorColor = [UIColor redColor];

// 隱藏分割線
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

// tableView有數(shù)據(jù)的時候才需要分割線
// 開發(fā)小技巧:快速取消分割線
 self.tableView.tableFooterView = [[UIView alloc] init];
//通常放廣告位的輪播圖
self.tableView.tableHeaderView = [[UIView alloc]init];

UITableViewCell的常見設(shè)置

// 取消選中的樣式(常用) 讓當(dāng)前 cell 按下無反應(yīng)
cell.selectionStyle = UITableViewCellSelectionStyleNone;

// 設(shè)置選中的背景色
UIView *selectedBackgroundView = [[UIView alloc] init];
selectedBackgroundView.backgroundColor = [UIColor redColor];
cell.selectedBackgroundView = selectedBackgroundView;

// 設(shè)置默認(rèn)的背景色
cell.backgroundColor = [UIColor blueColor];

// 設(shè)置默認(rèn)的背景色
UIView *backgroundView = [[UIView alloc] init];
backgroundView.backgroundColor = [UIColor greenColor];
cell.backgroundView = backgroundView;

// backgroundView的優(yōu)先級 > backgroundColor
// 設(shè)置指示器
//    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.accessoryView = [[UISwitch alloc] init];

數(shù)據(jù)刷新方法

  • 重新刷新屏幕上的所有cell
[self.tableView reloadData];
  • 刷新特定行的cell
[self.tableView reloadRowsAtIndexPaths:@[
        [NSIndexPath indexPathForRow:0 inSection:0],
        [NSIndexPath indexPathForRow:1 inSection:0]
        ]
        withRowAnimation:UITableViewRowAnimationLeft];
  • 插入特定行數(shù)的cell
[self.tableView insertRowsAtIndexPaths:@[
        [NSIndexPath indexPathForRow:0 inSection:0],
        [NSIndexPath indexPathForRow:1 inSection:0]
        ]
        withRowAnimation:UITableViewRowAnimationLeft];
  • 刪除特定行數(shù)的cell
[self.tableView deleteRowsAtIndexPaths:@[
        [NSIndexPath indexPathForRow:0 inSection:0],
        [NSIndexPath indexPathForRow:1 inSection:0]
        ]
        withRowAnimation:UITableViewRowAnimationLeft];

數(shù)據(jù)刷新的原則

  • 通過修改模型數(shù)據(jù),來修改tableView的展示
    • 先修改模型數(shù)據(jù)
    • 再調(diào)用數(shù)據(jù)刷新方法
  • 不要直接修改cell上面子控件的屬性

tableView如何顯示數(shù)據(jù)(UITableViewDataSource)

- 設(shè)置dataSource數(shù)據(jù)源
- 數(shù)據(jù)源要遵守UITableViewDataSource協(xié)議
- 數(shù)據(jù)源要實現(xiàn)協(xié)議中的某些方法


@required
//返回tableview的組數(shù)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
//返回Cell 的樣式
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

@optional
//返回每組有多少行
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
// 返回每組的頭部標(biāo)題
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
//返回每組的尾部標(biāo)題
- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
//返回是否進(jìn)入編輯狀態(tài)
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
//返回cell是否可以進(jìn)行移動
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
//返回一個數(shù)組 右側(cè)的索引,例如通訊錄的ABCD#
- (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
//設(shè)置索引欄標(biāo)題對應(yīng)的分區(qū)
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index ;
//tableView的cell編輯模式時 進(jìn)行操作時觸發(fā)的方法
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
//tableView的cell被移動時調(diào)用的方法
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;

tableView的代理方法(UITableViewDelegate)

//cell將要顯示時
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
//每組的頭視圖將要顯示時
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section;
//每組的尾視圖將要顯示時
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section;
//cell已經(jīng)顯示時
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath;
//每組的頭視圖已經(jīng)顯示時
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section;
//每組的尾部視圖已經(jīng)顯示時
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section;
//設(shè)置行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
//組頭高度(有時候組頭顯示不出來可能是忘記調(diào)用該方法)
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
//設(shè)置每組尾部視圖高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
//設(shè)置每行的預(yù)估高度(調(diào)用此方法性能比不掉好100倍)
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath*)indexPath;
//設(shè)置組頭預(yù)估高度
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section;
//設(shè)置組尾預(yù)估高度
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section;
//自定義組頭
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
//自定義組尾
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
//設(shè)置cell是否可以高亮
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath;
//cell高亮?xí)r調(diào)用
- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath;
//cell取消高亮?xí)r調(diào)用
- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath;
//返回即將選中某行調(diào)用,返回某行位置
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
//返回即將取消選中某行
- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath*)indexPath;
//已經(jīng)選中某行(cell  點擊事件處理)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
//取消選中(經(jīng)常配合選中某行方法使用)
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath;
//設(shè)置編輯狀態(tài),默認(rèn)刪除狀態(tài)
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
//自定義刪除按鈕的標(biāo)題
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
//下面這個方法是IOS8中的新方法,用于自定義創(chuàng)建tableView被編輯時右邊的按鈕,按鈕類型為UITableViewRowAction。
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath;
//設(shè)置編輯時背景是否縮進(jìn)
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;
//將要編輯時調(diào)用
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath;
//取消編輯時調(diào)用
- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath;
//移動特定的某行
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath;

一個tableview功能介紹的小Demo

等高Cell

等高CELL.jpeg

編輯狀態(tài)

//設(shè)置編輯屬性 進(jìn)入編輯狀態(tài),也可設(shè)置進(jìn)入編輯狀態(tài)是否需要動畫
    [self.tableView setEditing:!self.tableView.editing animated:YES];
  • 刪除和添加的編輯狀態(tài)
刪除.jpeg
添加.jpeg

//編輯狀態(tài)的事件處理
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
//刪除狀態(tài)是點擊了右邊的刪除才會觸發(fā)  并不是點擊左邊的減號
    if (editingStyle == UITableViewCellEditingStyleDelete) {  // 點擊了“刪除”
        [self.dataSource removeObjectAtIndex:indexPath.row];
        [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
    }else if (editingStyle == UITableViewCellEditingStyleInsert){//點擊了添加 
        [self.dataSource insertObject:self.dataSource[indexPath.row] atIndex:indexPath.row];
        [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
    }
}
//返回當(dāng)前的編輯狀態(tài) (需要同時實現(xiàn)編輯事件的處理方法 才會有效果)
@property (nonatomic,assign)UITableViewCellEditingStyle style;

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
//默認(rèn)編輯狀態(tài)是刪除狀態(tài)
    return   self.style;
}

  • 自定義刪除按鈕的標(biāo)題
側(cè)滑刪除按鈕標(biāo)題的自定義.jpeg
//自定義刪除時的按鈕標(biāo)題
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{
//可以根據(jù)indexPath自定義任何行的刪除標(biāo)題
    if(indexPath.row ==0){
    
        return @"自定義";
    }
    return @"刪除";

}
  • 批量操作
批量.jpeg
//設(shè)置這個屬性為yes 可進(jìn)入多選模式
self.tableView.allowsMultipleSelectionDuringEditing
//從這個方法這樣返回一個進(jìn)入編輯模式(個人認(rèn)為這是非主流的黑魔法)
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
   return  UITableViewCellEditingStyleDelete |    UITableViewCellEditingStyleInsert  
}
//刪除操作
// 獲得所有被選中的行
        NSArray *indexPaths = [self.tableView indexPathsForSelectedRows];
        // 便利所有的行號
        NSMutableArray *deletedDeals = [NSMutableArray array];
        for (NSIndexPath *path in indexPaths) {
            [deletedDeals addObject:self.dataSource[path.row]];
        }
        // 刪除模型數(shù)據(jù)
        [self.dataSource removeObjectsInArray:deletedDeals];
        // 刷新表格  一定要刷新數(shù)據(jù)
        [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationRight];
  • cell移動
移動.jpeg
//返回 cell 是否可以移動
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    //多選狀態(tài)為NO 編輯狀態(tài)為 0 (UITableViewCellEditingStyleNone)時才可以移動 否則其他編輯狀態(tài)會干擾移動
    return !self.style && !self.tableView.allowsMultipleSelectionDuringEditing;
}
//移動操作結(jié)束的回調(diào)方法,可以獲得cell初始位置和 移動后的位置
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    //更新數(shù)據(jù)源
    [self.dataSource exchangeObjectAtIndex:sourceIndexPath.row withObjectAtIndex:destinationIndexPath.row];
}

類似好友分組

  • 一個可以展開和合并的非主流分組(我不是腦殘?。┯覀?cè)帶有組標(biāo)題的索引

  • 兩個模型

  • 組模型

@interface SectionModal : NSObject
//組名
@property (nonatomic,copy)NSString * title;
//組成員數(shù)組
@property (nonatomic,copy)NSArray * member;
//展開關(guān)閉狀態(tài)
@property (nonatomic,assign)BOOL state;

+(instancetype)sectionWithDic:(NSDictionary *)dic;
@end
  • 人模型
@interface PersonModal : NSObject
//姓名
@property (nonatomic,copy)NSString * name;
//頭像
@property (nonatomic,copy)NSString * icon;
//簽名
@property (nonatomic,copy)NSString * circle;
+ (instancetype)personWithDic:(NSDictionary *)dic;
@end
//返回每組的行數(shù)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    SectionModal * sec = self.dataSource[section];
    //展開狀態(tài)
    if (sec.state) {
        return sec.member.count;
    }
    //關(guān)閉狀態(tài)返回0
    return 0;

}
//自定義組頭(會復(fù)用,性能不好)
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
    SectionModal * sec = self.dataSource[section]; 
    SectionHeadView *  sectionView = [[[NSBundle mainBundle]loadNibNamed:NSStringFromClass([SectionHeadView class]) owner:nil options:nil]lastObject];
    sectionView.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 50);
    sectionView.section = sec;
    __weak typeof(self) weakSelf = self;
    __weak typeof(sec) weakSec = sec;

    //組頭點擊的block
    sectionView.block = ^(){

        //改變每組的展開狀態(tài) 
        weakSec.state = ! weakSec.state;
        //刷新tableview
        [weakSelf.tableView reloadSections:[[NSIndexSet alloc]initWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
    };
    return sectionView;
}
  • 展開時
好友分組.jpeg
  • 全部合并時 (傳說中的非主流分組,右側(cè)藍(lán)色的是索引?。。。。?/li>
一大波腦殘非主流來了.jpeg
//右側(cè)索引
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    NSMutableArray * indexArr =[NSMutableArray array];
    for (SectionModal * modal in self.dataSource) {
        [indexArr addObject:modal.title];
    }
    return indexArr;
}
  • 自定義多個編輯按鈕
側(cè)滑編輯按鈕自定義.jpeg

//UITableViewRowAction。左滑  刪除 置頂 等編輯選項 (iOS8以后)
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
    //UITableViewRowActionStyleDefault = 0,
    //    UITableViewRowActionStyleDestructive = UITableViewRowActionStyleDefault,
    //    UITableViewRowActionStyleNormal
    UITableViewRowAction * action = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"刪除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        NSLog(@"刪除");
    }];
    action.backgroundColor = [UIColor redColor];
    UITableViewRowAction * action1 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"標(biāo)為未讀" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {    
        NSLog(@"標(biāo)為未讀");
    }];
    action1.backgroundColor = [UIColor orangeColor];
    UITableViewRowAction * action2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"置頂" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {   
        NSLog(@"置頂");
    }];
    action2.backgroundColor = [UIColor grayColor]; 
    return @[action,action1,action2];   
}

非等高Cell

一個簡單仿照朋友圈的列表

簡單的非等高cell.jpeg

關(guān)鍵在于cell高度的處理,數(shù)據(jù)模型中加入一個cellHeight屬性

@interface CircleModal : NSObject
//文字狀態(tài)
@property (nonatomic,copy)NSString * text;
//頭像
@property (nonatomic,copy)NSString * icon;
//昵稱
@property (nonatomic,copy)NSString * name;
//圖片狀態(tài)
@property (nonatomic,copy)NSString * picture;
//是否是vip
@property (nonatomic,copy , getter=isVip)NSNumber * vip;
//行高
@property (nonatomic,assign)CGFloat cellHeight;
+(instancetype)circleWithDic:(NSDictionary *)dic;
@end

在cell的Set方法中布局完成后獲得高度 賦給模型

-(void)setCircle:(CircleModal *)circle{

    _circle = circle;
    self.headImageView.image = [UIImage imageNamed:circle.icon];
    self.nameLabel.text = circle.name;
    if([circle.isVip  isEqual: @(1)] ){
        self.vipImageView.hidden = NO;
        self.nameLabel.textColor = [UIColor orangeColor];
    }else{
        self.vipImageView.hidden = YES;
        self.nameLabel.textColor = [UIColor blackColor];
    }
    self.contentLabel.text = circle.text;
    if(circle.picture){
        self.photoImageView.image = [UIImage imageNamed:circle.picture];
        self.photoImageView.hidden = NO;
    }else{
        self.photoImageView.hidden=YES;
    }
    // 強(qiáng)制布局
    [self layoutIfNeeded];  
    // 計算cell的高度
    if (self.photoImageView.hidden) { // 沒有配圖
        circle.cellHeight = CGRectGetMaxY(self.contentLabel.frame) + 10;
    } else { // 有配圖
        circle.cellHeight = CGRectGetMaxY(self.photoImageView.frame) + 10;
    }
}

如此在控制器中就可以拿到cell的高度

//返回行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CircleModal * circle = self.dataSource[indexPath.row];
    return circle.cellHeight;
}

但是!??! 一定要注意,一定要實現(xiàn)下面這個方法,以前只知道這個方法可以優(yōu)化性能,如果這個方法不實現(xiàn),tableview 會在 (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 這個cell創(chuàng)建方法調(diào)用之前 多次調(diào)用上面返回行高的方法,此時cell還是nil會導(dǎo)致程序崩潰,實現(xiàn)了下面 預(yù)估行高的方法,tableview創(chuàng)建cell前就不會調(diào)用上面的方法!

通過打印日志可以看出 如果不實現(xiàn)下面方法 創(chuàng)建cell前 每個row創(chuàng)建之前都要調(diào)用三遍heightForRowAtIndexPath,這樣一次性調(diào)用了幾十遍,實現(xiàn)了estimatedHeightForRowAtIndexPath,后tableview 每次先創(chuàng)建cell然后返回一次rowHeight,這就是下面這個方法解決性能的由來!

//返回一個預(yù)估的高度 (配合cellHeight的使用必須實現(xiàn)這個代理方法)
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 200;
}

仿照聊天消息界面

仿聊天.jpeg

左右兩種cell,每個消息是一個模型,通過MessageModal中的type參數(shù)來區(qū)分是我發(fā)給別人的消息還是別人發(fā)給我的消息

//返回cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 
    MessageModal * message = self.dataSource[indexPath.row];
    NSString * ID = [message.type isEqual:@(1)] ? @"me":@"other";
    MessageCell * cell = [tableView dequeueReusableCellWithIdentifier:ID]; 
    if (!cell) {
        //根據(jù)type 在我的cell和他人的cell中進(jìn)行選擇
        NSString * xibName = [message.type isEqual:@(1)] ? @"MeMessageCell":@"OtherMessageCell";    
       cell = [[[NSBundle mainBundle] loadNibNamed:xibName owner:nil options:nil] lastObject];
    }  
    cell.message = message;
    return cell;  
}

看似簡單,還是遇到了許多問題,尤其是在計算高度的時候,聊天內(nèi)容選擇的是btn 因為有個背景圖,然后發(fā)現(xiàn)用button處理一些文字計算高度,遠(yuǎn)遠(yuǎn)不如label簡單

-(void)setMessage:(MessageModal *)message{
    _message = message;
    if (message.hiddenTime) { // 隱藏時間
        self.timeLabel.hidden = YES;
        [self.timeLabel updateConstraints:^(MASConstraintMaker *make) {
            make.height.equalTo(0);
        }];
    } else { // 顯示時間
        self.timeLabel.text = message.time;
        self.timeLabel.hidden = NO;
        [self.timeLabel updateConstraints:^(MASConstraintMaker *make) {
            make.height.equalTo(21);
        }];
    }  
//約束設(shè)置完后必須強(qiáng)制更新下,才會拿到真正的frame等尺寸  
    [self layoutIfNeeded];
    [self.contentBtn setTitle:message.text forState:UIControlStateNormal];   
    UIImage * imageNormal;
    UIImage * imageHilight; 
//判斷是我發(fā)的消息,還是收的消息
    if ([message.type isEqual:@(1)]) {
        imageNormal = [UIImage imageNamed:@"chat_send_nor"];   
        imageHilight = [UIImage imageNamed:@"chat_send_press_pic"];  
    }else{    
        imageNormal = [UIImage imageNamed:@"chat_recive_nor"];      
        imageHilight = [UIImage imageNamed:@"chat_send_recive_pic"];       
   }
    //拉伸聊天內(nèi)容的背景圖片
    imageNormal = [imageNormal stretchableImageWithLeftCapWidth:imageNormal.size.width * 0.5 topCapHeight:imageNormal.size.height * 0.5];
    imageHilight = [imageHilight stretchableImageWithLeftCapWidth:imageHilight.size.width * 0.5 topCapHeight:imageHilight.size.height * 0.5];
    //給按鈕設(shè)置內(nèi)邊距(不然文字顯示會有問題)
    self.contentBtn.contentEdgeInsets = UIEdgeInsetsMake(10, 15, 10, 15);
    [self.contentBtn setBackgroundImage:imageNormal forState:UIControlStateNormal];
    [self.contentBtn setBackgroundImage:imageHilight forState:UIControlStateHighlighted];  
    [self layoutIfNeeded];  
    // 設(shè)置按鈕的高度就是titleLabel的高度
    [self.contentBtn updateConstraints:^(MASConstraintMaker *make) {
        CGFloat buttonH = self.contentBtn.titleLabel.frame.size.height + 30;
        make.height.equalTo(buttonH);
    }]; 
    // 強(qiáng)制更新
    [self layoutIfNeeded];
    //獲得頭像的最大Y與文字內(nèi)容的最大Y
    CGFloat timeLabelMaxY = CGRectGetMaxY(self.timeLabel.frame);
    CGFloat contentBtnMaxY = CGRectGetMaxY(self.contentBtn.frame);
    //兩者較大的就是行高
    message.cellHeight = MAX(timeLabelMaxY, contentBtnMaxY)+10;
}

Demo地址(https://github.com/heiheiLqq/UITableVIewDemo

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

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

  • #pragma mark someValueAboutTableView 1.tableView的樣式:UITab...
    瀟巖閱讀 1,049評論 0 0
  • UITableViewCell控件空間構(gòu)造 cell的子控件是contentView,contentView的子控...
    CoderZXS閱讀 845評論 0 1
  • 概述在iOS開發(fā)中UITableView可以說是使用最廣泛的控件,我們平時使用的軟件中到處都可以看到它的影子,類似...
    liudhkk閱讀 9,289評論 3 38
  • 版權(quán)聲明:未經(jīng)本人允許,禁止轉(zhuǎn)載. 1. TableView初始化 1.UITableView有兩種風(fēng)格:UITa...
    蕭雪痕閱讀 2,983評論 2 10
  • { 24、Sqlite數(shù)據(jù)庫 1、存儲大數(shù)據(jù)量,增刪改查,常見管理系統(tǒng):Oracle、MSSQLServer、DB...
    CYC666閱讀 1,047評論 0 1

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