UITableViewCell高度自適應探索--AutoLayout結合Frame

UITableViewCell高度自適應探索--UITableView+FDTemplateLayoutCell
地址: http://www.jianshu.com/p/7839e3a273a6
UITableViewCell高度自適應探索--cell預估高度(一)
地址: http://www.jianshu.com/p/6ab92579fcf1
UITableViewCell高度自適應探索--cell預估高度(二)
地址: http://www.jianshu.com/p/f3609cd9392e
今天,再提供一種AutoLayout與Frame相結合的方式來設置cell高度的方法.git

今天這個方法的要點是:github

  • 使用Autolayout在進行佈局.
  • 使用Frame進行高度計算
  • 使用模型的屬性緩存每一個Cell第一次計算的高度.

相對於以前說的那些方法,這個方法比UITableView+FDTemplateLayoutCell使用起來更簡單和容易理解(自從寫FD那篇文章發表後收到不少網友的關於使用的問題,大部分是因爲沒有使用正確);而且克服了預估高度方式的那些問題,也不用把約束改來改去, 使計算的過程更加可控.緩存

這種方法雖然是使用fram的方式計算,可是若是沒有autoLayout,計算的過程就會複雜幾倍,有時候可能還須要一個專門的類去管理子控件的frame.在我看來是一個比較不錯的方法.ide

進入正題.佈局

先看要實現的效果:atom


目標效果

其中文字的長度不一,圖片可能有或沒有.爲了排除其餘干擾,數據來自plist文件.spa

  • 這是咱們自定義cell的設置,這些元素是固定的,咱們使用AutoLayout對它們幾個進行佈局.

cell佈局
  • 建立一個Message模型,賦予其對應的屬性.
    因爲cell的高度本質上仍是基於模型數據來算的,因此計算高度的任務交給模型,故模型同時開放一個cellHeight的只讀屬性,未來好拿給控制器使用.
1 @interface Message : NSObject
2 
3 // 頭像、名字、和描述文字我給固定了,因此沒有弄屬性處理
4 @property (nonatomic, copy) NSString *imageName;
5 @property (nonatomic, copy) NSString *content;
6 @property (nonatomic, assign, readonly) CGFloat cellHeight;
7 
8 @end
View Code

 

  • 模型計算Cell高度,經過重寫cellHeight的getter方法實現
 1 - (CGFloat)cellHeight {
 2     if (!_cellHeight) {
 3         CGFloat contentW = [UIScreen mainScreen].bounds.size.width - 2 * margin; // 屏幕寬度減去左右間距
 4         CGFloat contentH = [self.content boundingRectWithSize:CGSizeMake(contentW, MAXFLOAT)
 5                                                       options:NSStringDrawingUsesLineFragmentOrigin
 6                                                    attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:contentFont]}
 7                                                       context:nil].size.height;
 8         _cellHeight = contentLabelY + contentH + margin;
 9     }
10     return _cellHeight;
11 }
View Code

 

注意:
上面高度的計算尚未將內容圖片的高度計算在內.
而且實現了利用模型的cellHeight屬性緩存第一次計算高度.
  • 因爲內容圖片不是每一個cell都有,因此使用代碼動態添加.
 1 // 屬性聲明
 2 @property (strong, nonatomic) UIImageView *contentImageView;
 3 // getter實現
 4 - (UIImageView *)contentImageView {
 5     if (!_contentImageView) {
 6         _contentImageView = [[UIImageView alloc] init];
 7         [self.contentView addSubview:_contentImageView];
 8     }
 9     return _contentImageView;
10 }
View Code

 

  • cell該接收模型了
 1 @property (nonatomic, strong) Message *message;
 2 - (void)setMessage:(Message *)message {
 3     _message = message;
 4     self.contentLabel.text = _message.content;
 5     if (message.imageName.length) {
 6         self.contentImageView.hidden = NO;
 7         self.contentImageView.image = [UIImage imageNamed:message.imageName];
 8     }
 9     else {
10         self.contentImageView.hidden = YES;
11     }
12 }
View Code

 

固然,這時候contentImageView固然是顯示不出來的,由於咱們尚未贈送它一個frame.那麼它的frame從何而來呢?code

一開始咱們說過,計算要基於模型,因此接下來的思路是由模型算出imageView的frame,拿去給cell用.blog

回到模型cellHeight的getter方法,添加對imageName屬性的處理:圖片

 1 // 圖片將要展現的frame做爲模型的其中一個屬性
 2 @property (nonatomic, assign) CGRect contentImageFrame;
 3 - (CGFloat)cellHeight {
 4     if (!_cellHeight) {
 5         CGFloat contentW = [UIScreen mainScreen].bounds.size.width - 2 * margin; // 屏幕寬度減去左右間距
 6         CGFloat contentH = [self.content boundingRectWithSize:CGSizeMake(contentW, MAXFLOAT)
 7                                                       options:NSStringDrawingUsesLineFragmentOrigin
 8                                                    attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:contentFont]}
 9                                                       context:nil].size.height;
10         _cellHeight = contentLabelY + contentH + margin;
11 
12         // 對imageName屬性的處理
13         if (self.imageName.length) {
14             UIImage *image = [UIImage imageNamed:self.imageName];
15             CGFloat imageH = image.size.height;
16             CGFloat imageW = image.size.width;
17             // 直接得出contentImageView應該顯示的frame
18             _contentImageFrame = CGRectMake(margin, _cellHeight, imageW, imageH);
19             _cellHeight += imageH + margin;
20         }
21     }
22     return _cellHeight;
23 }
View Code

當上面代碼執行完畢,contentImageFrame就有值了.接着,回到cell的setMessage:方法給contentImageView賦值.
 1 - (void)setMessage:(Message *)message {
 2     _message = message;
 3     self.contentLabel.text = _message.content;
 4     if (message.imageName.length) {
 5         self.contentImageView.hidden = NO;
 6         self.contentImageView.image = [UIImage imageNamed:message.imageName];
 7         // 給圖片的frame賦值,這個值就是上面獲得那個
 8         self.contentImageView.frame = _message.contentImageFrame;
 9     }
10     else {
11         self.contentImageView.hidden = YES;
12     }
13 }
View Code

 

  • 這時候使用起來就很是輕鬆了
1 // 控制器tableView協議方法實現
2 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
3     Message *message = self.dataList[indexPath.row];
4     return message.cellHeight;
5 }
View Code

 


完整代碼下載:
https://github.com/CoderAO/AutoCellHeightMix
相關文章
相關標籤/搜索