天天看點

使用autolayout自定義動态高度的cell

關于使用autolayout建立動态cell,網上也有不少的文章,但是裡面的内容都是說的一個問題,簡稱換湯不換藥,都是說的一些UILabel或者UITextView等等一些控件顯示的文本内容不同來實作不同的高度。

但是我們平常使用的自定義cell很多都是顯示不同數量的控件,來顯示不同的高度,比如微網誌首頁,餓了麼首頁那些cell,都是下面顯示不同數量的控件來顯示不同高度的cell,那麼下面就讓我們一起看看怎麼使用autolayout實作這種自定義cell

關于使用autolayout實作cell動态高度有兩種實作方式

iOS8以後

iOS8以後比較爽:隻需要設定下面兩句代碼就行了

//設定cell的估計高度
self.tableView.estimatedRowHeight = ;

//iOS以後這句話是預設的,是以可以省略這句話
self.tableView.rowHeight = UITableViewAutomaticDimension;
           

你可能沒有看到實作代理方法傳回cell高度。明确告訴你iOS8以後不需要實作了,系統會自動推斷出cell的高度。

but,iOS7還是需要

下面就是iOS7實作的方式,還是需要實作這個方法,iOS8那兩句代碼不寫也可以

//如果要支援iOS7這個方法必須實作
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    //其他代碼

    //自動算高度,+1的原因是因為contentView的高度要比cell的高度小1
    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + ;

    return height;
}
           

主要就是下面這句代碼,能自動計算出contentView的高度和寬度

上面這兩種方式可以一起存在,既支援ios7也支援iOS8.

開始demo

先來看一下我們最終的效果:

使用autolayout自定義動态高度的cell
  • 有的cell隻有一個UITextLabel,并且label會根據内容的多少來改變高度
  • 有的cell下面還有一個UIButton,并且cell會根據有沒有button來動态改變高度

實作思路

- 首先自定義一個cell,順便建立一個xib檔案

- 在xib檔案中把所有包含的控件全部搞上去,設定好限制

- 如果不需要哪個控件顯示就把哪個控件的高限制設定為0

- 如果需要顯示哪個控件就保證這個控件沒有高度限制(應該容易想的到因為是動态高度的cell,是以不能有高度的限制)

- 然後更新限制,顯示cell

在這裡我們使用xib的方式建立自定義cell

如圖:

使用autolayout自定義動态高度的cell

這裡設定限制有幾個注意點

  • 每一個控件都隻設定上下左右的限制,不設定寬高的限制,有些必須要固定大小的可以設定一下
  • 有些控件如果不設定寬高xib會報錯的話,就設定占位符placehoder
  • 像一些要消失或者顯示的控件,最好設定他與其他顯示的控件間距為0

這是我自定義cell的類

使用autolayout自定義動态高度的cell

在控制器中我們實作資料源代碼

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.tableView registerNib:[UINib nibWithNibName:@"MyTableViewCell" bundle:nil] forCellReuseIdentifier:@"cell"];

    self.tableView.allowsSelection = NO;

    //胡亂寫的,為了懶省事,大家湊合着看吧
    self.tableData = @[@"1\n2\n3\n4\n5\n6", @"123456789012345678901234567890", @"1\n2", @"1\n2\n3", @"123456789012345678901234567890", @"1\n2\n3\n4\n5\n6", @"123456789012345678901234567890", @"1\n2", @"1\n2\n3", @"123456789012345678901234567890", @"1\n2\n3",@"1\n2\n3",@"123456789012345678901234567890", @"1\n2", @"1\n2\n3", @"123456789012345678901234567890", @"1\n2\n3",@"1\n2\n3"@"123456789012345678901234567890", @"1\n2", @"1\n2\n3", @"123456789012345678901234567890", @"1\n2\n3",@"1\n2\n3"@"123456789012345678901234567890", @"1\n2", @"1\n2\n3", @"123456789012345678901234567890", @"1\n2\n3",@"1\n2\n3"@"123456789012345678901234567890", @"1\n2", @"1\n2\n3", @"123456789012345678901234567890", @"1\n2\n3",@"1\n2\n3"@"123456789012345678901234567890", @"1\n2", @"1\n2\n3", @"123456789012345678901234567890", @"1\n2\n3",@"1\n2\n3"];
}


-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return ;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.tableData.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];

    cell.text = self.tableData[indexPath.row];

    return cell;
}
           

我們先使用iOS8的方法

接下來就是去自定義cell類(MyTableView.m)中重寫-updateConstraints 方法

-(void)updateConstraints {
    //remove Constraints
    [self.height uninstall];

    //add Constraints
    [self.content mas_makeConstraints:^(MASConstraintMaker *make) {
       self.height = make.height.equalTo(@60);//any number
    }];

    if(self.isShowView == NO) {
        //change Height Constrains to be 
        [self.content mas_updateConstraints:^(MASConstraintMaker *make) {
            make.height.equalTo(@0);
        }];
    }
    else {
        //remove Constraints
        [self.height uninstall];
    }

    [super updateConstraints];
}
           
  • 如果不需要顯示就設定高度限制為0
  • 如果需要顯示就把高度限制去掉

這個方法超級重要,有些view需要顯示的話,一定要把高度限制去掉,不然cell循環使用的話會出問題。

然後就是設定要顯示的text

-(void)setText:(NSString *)text {
    _text=text;
    self.textView.text = text;

    if ([self.text isEqualToString:@"123456789012345678901234567890"]) {
        self.isShowView = NO;
        self.button.hidden=YES;
        self.content.hidden=YES;
        self.intextView.hidden=YES;
    }else {
        self.isShowView = YES;
        self.button.hidden=NO;
        self.content.hidden=NO;
        self.intextView.hidden=NO;

    }
}
           

接下來在Controller檔案中

将cellForRowAtIndexPath方法改為下面樣子

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];

    cell.text = self.tableData[indexPath.row];

    //傳回cell之前重新重新整理限制,重新計算高度
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    return cell;
}
           

然後在-viewDidLoad方法中增加兩句話就行了

self.tableView.estimatedRowHeight = ;
self.tableView.rowHeight = UITableViewAutomaticDimension;
           

接下來是支援iOS7的

隻需要重寫代碼方法heightForRowAtIndexPath

将這個方法内容改為下面這樣:

//如果要支援iOS7這個方法必須實作
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    self.cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"cell"];


    MyTableViewCell *cell = self.cell;
    cell.text = [self.tableData objectAtIndex:indexPath.row];

    //這句代碼必須要有,也就是說必須要設定contentView的寬度限制。
    //設定以後,contentView裡面的内容才知道什麼時候該換行了
    CGFloat contentViewWidth = CGRectGetWidth(self.tableView.frame);
    [cell.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.width.equalTo(@(contentViewWidth));
    }];

    //重新加載限制,每次計算之前一定要重新确認一下限制
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    //自動算高度,+1的原因是因為contentView的高度要比cell的高度小1
    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + ;

    return height;
}
           

關注我的新部落格吧!

我的新部落格位址:(http://www.codertian.com)

好了大概就是這樣吧,具體demo點這裡

繼續閱讀