使用UITableView+FDTemplateLayoutCell高度緩存以及實現文本展開全文和收起功能
看到這個標題,我知道你肯定是想學習下如何實現UITableView的高度緩存或者是剛好有個需求是實現展開和收起的功能吧,下面我挨個來講吧:
*先說這個牛逼的UITableView+FDTemplateLayoutCell,先來說說怎么使用這個庫吧,其實總結起來就兩步:
1.先注冊cell(而且必須注冊):
[self.tableView registerClass:[CMDebunkCell class] forCellReuseIdentifier:@"CMDebunkCell"];
2.在返回tableView高度的代理方法中實現以下方法:
CMEvent *model = [self.dataArray objectAtIndex:indexPath.row];
return [tableView fd_heightForCellWithIdentifier:@"CMDebunkCell" configuration:^(id cell) {
CMDebunkCell * debunkCell = (CMDebunkCell *)cell;
[debunkCell configCellWithModel:model indexPath:indexPath];
}];
總共就兩步是不是很簡單,但是有一個注意點也是使用這個庫比較重要的地方:一定要在設置cell約束的時候給cell.contentView的底部約束設置好了,例如我在自定義的cell中這么寫:
[self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.top.mas_equalTo(self);
make.bottom.mas_equalTo(self.textView).offset(5);
}];
這樣我就確定了它的底部約束了,細心的你是不是已經發現貌似這和高度緩存沒卵關系,好吧,那我下面就接著高度緩存的話題來說吧,剛剛在返回tableView高度的代理方法中我實現的一個方法是這個庫自帶的自動計算高度的方法,這個方法是沒有帶緩存功能的,它還提供了另外一個方法用與緩存高度:
[tableView fd_heightForCellWithIdentifier:@"CMDebunkCell" cacheByKey:model.id configuration:^(id cell) {
CMDebunkCell * debunkCell = (CMDebunkCell *)cell;
[debunkCell configCellWithModel:model indexPath:indexPath];
}];
這里的cacheByKey是用與緩存的唯一標識,我這里的model.id是服務器返回給我的標識這一個cell的,當然作者還很貼心的提供了另外一個根據indexPath來緩存的方法:
[tableView fd_heightForCellWithIdentifier:@"CMDebunkCell" cacheByIndexPath:indexPath configuration:^(id cell) {
CMDebunkCell * debunkCell = (CMDebunkCell *)cell;
[debunkCell configCellWithModel:model indexPath:indexPath];
}];
對于大多數人來說,使用以上兩個方法就可以實現cell高度緩存以及自動計算行高的功能了,但是可能會有一些情形例如:當cell的高度是動態變化的怎么辦呢?
這就到了我們的第二個話題,那就是怎么實現展開和收起的功能,我先貼個效果圖吧:
2016-07-21 16_21_36.gif
從效果圖可以看到,點擊全文,文本會展開,點擊收起文本自動縮回,當然高度肯定是要跟著變化的,下面貼上代碼吧:
//折疊或者展開按鈕
self.foldBtn = [[UIButton alloc]init];
[self.contentView addSubview:self.foldBtn];
self.foldBtn.titleLabel.font = [UIFont systemFontOfSize:15];
self.foldBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
[self.foldBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[self.foldBtn addTarget:self action:@selector(foldContentOrNo:) forControlEvents:UIControlEventTouchUpInside];
[self.foldBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.content);
make.top.equalTo(self.content.mas_bottom).offset(PADDINGMARGIN);
make.width.mas_equalTo(100);
make.height.mas_equalTo(30);
}];
/**
* 折疊或者展開事件
*
* @param foldBtn 折疊或展開按鈕
*/
- (void)foldContentOrNo:(UIButton *)foldBtn {
NSAssert(self.foldOrNoBlock !=nil, @"傳入的折疊或者展開block不為nil");
self.foldOrNoBlock(foldBtn);
}
self.foldOrNoBlock是我在自定義cell里面定義的回調block,它在控制器是這么寫的:
//折疊或展開block
cell.foldOrNoBlock = ^(UIButton * foldBtn){
//獲取所在按鈕的cell
CMDebunkCell * curCell = (CMDebunkCell *)[[foldBtn superview] superview];
//獲取所在索引
NSIndexPath * indexPath = [weakSelf.tableView indexPathForCell:curCell];
model.is_Open = !model.is_Open;
[weakSelf.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
};
在這個方法中你要注意的就是這個 model.is_Open,就是通過模型里面的is_Open這個屬性來控制展開和收起的功能,下面就得說數據部分了,到底什么時候我們需要折疊呢,這個肯定是看你們的需求了,我這里就直接按字數來了,你也可以根據計算文本超過多少行之后來判斷是收起還是展開,
//文本內容
self.content.text = model.content.text;
if (model.content.length >300) {
self.foldBtn.hidden = NO;
if (model.is_Open) {
self.content.numberOfLines = 0;
[_foldBtn setTitle:@"收起" forState:UIControlStateNormal];
}else {
self.content.numberOfLines = 4;
[_foldBtn setTitle:@"全文" forState:UIControlStateNormal];
}
}else {
self.content.numberOfLines = 0;
self.foldBtn.hidden = YES;
}
好吧,代碼基本上就到這里了,上面的代碼應該很容易看懂,當字數超過300(具體什么條件自己決定),根據模型的is_Open這個屬性來決定展開和收起,展開和收起這里我是通過控制行數,當然你也可以通過限制它的高度來,SDAutoLayout這個庫有興趣可以去看看,它里面有個微信的demo就是根據控制高度來實現的,
下面我覺得該說說重頭戲了,當文本要展開時高度怎么變化,收起時又怎么變化?
前面我們說了UITableView+FDTemplateLayoutCell這個分類牛逼的地方就在于自動計算行高了,如果我們在沒有緩存的情況下,只要你使用了它其實高度的計算不需要我們來管,我們只需要[self.tableView reloadData]就完全足夠了,但是如果有緩存的時候,這個問題就來了,你會發現,點擊展開布局會亂,有一部分會看不到,這是因為高度并沒有變化,一直用的是緩存的高度,所以解決辦法如下(當然這是我的解決方案,有更好的,或者覺得我這個方案有問題也希望你能issue我):
在返回高度的代理方法中,根據展開和收起的標識也就是上面提到的is_Open來決定返回哪個高度:
//返回cell高度代理方法
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CMEvent *model = [self.dataArray objectAtIndex:indexPath.row];
if (model.content.is_Open) {
return [tableView fd_heightForCellWithIdentifier:@"CMDebunkCell" configuration:^(id cell) {
CMDebunkCell * debunkCell = (CMDebunkCell *)cell;
[debunkCell configCellWithModel:model indexPath:indexPath];
}];
}else {
return [tableView fd_heightForCellWithIdentifier:@"CMDebunkCell" cacheByKey:model.id configuration:^(id cell) {
CMDebunkCell * debunkCell = (CMDebunkCell *)cell;
[debunkCell configCellWithModel:model indexPath:indexPath];
}];
}
}
來自:http://www.jianshu.com/p/d84dc5051be0