iOS-AutoLayout還不會,你就累到死

花時間寫了個Demo,包含比較全面從UIView,UILabel,UIImageView的自適應到UITextView,UITableView,UICollectionView,UIScrollView都有,可以下載學習一下。Demo地址
注意不配合demo也許會不知所云!

Demo列表

iOS8之後 使用AutoLayout是非常方便的,更何況iOS11都要發佈了,不會還想着支持iOS7吧!(iOS7也是支持autolayout的,只是有一些坑及與iOS8API的不同)。

iOS8以後,對於UIScrollView及UITableView,UICollectionViewCell的高度自適應解決了我們一直頭疼的變高問題!!!

如果你還不用,那麼你覺得你是偷懶了,懶得去學,其實你在開發中浪費了更多的時間與腦細胞。

UIView的自適應

UIView可以根據其subviews自動適配自己的寬高,也就是如果其subviews能有明確的足夠的約束信息,那麼view的寬高就可以被確定了

UILabel的自適應

有時候如果想UILabel的文字增多變寬變高,要如何實現?其實UILabel是一個比較特殊的元素,只要設置了寬度約束,高度就會自適應了(UILabel設置lines=0表示自動換行,具體數字是限制多少行)。如我們給UILabel設置約束寬度不大於200,然後動態改變它上邊的文字,它就自適應了高度

UIImageView

看到網上好多人問如何處理圖片自適應的問題,比如固定imageView的寬度,高度根據網絡獲取的image來動態改變。很遺憾,UIImageView並沒有自動佈局。我們可以讓後臺返回寬高,或者請求到image對象後,根據image的size來獲取寬高。然後根據寬高的縮放比例來適配

[self.imageViewRef mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.contentView);
}];
customCell.imageViewRef.image = image;
[customCell.imageViewRef mas_updateConstraints:^(MASConstraintMaker *make) {
    make.height.mas_equalTo([UIScreen mainScreen].bounds.size.width * image.size.height / image.size.width);
 }];

UITextView的高度自適應

要點:

  • UITextView的高度自適應只需要不限制其height
  • scrollEnabled = NO 只有不可滾動纔會自動擴展其高度
  • 若textView的內容發生偏移,請看UITextView內容偏移的問題處理
 - (UITextView *)textView
{
    if (!_textView) {
        _textView = [[UITextView alloc] init];
        _textView.backgroundColor = [UIColor grayColor];
        _textView.scrollEnabled = NO;
        _textView.font = [UIFont systemFontOfSize:20];
    }
    return _textView;
}

 - (void)makeContraints
{
    WEAKSELF
    [self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(weakSelf.view);
        make.top.mas_equalTo(100);
        make.height.greaterThanOrEqualTo(@100);
    }];
}

UITableViewCell的自適應

*兼容iOS7 時
systemLayoutSizeFittingSize來取高。步驟是先在數據model中添加一個height的屬性用來緩存高,然後在table view的heightForRowAtIndexPath代理裏static一個只初始化一次的Cell實例,然後根據model內容填充數據,最後根據cell的contentView的systemLayoutSizeFittingSize的方法獲取到cell的高,然後緩存給model的height

//還是那個熟悉的高度的代理,iOS8之後就少用它吧
 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    static CustomCell *cell;
    //只初始化一次cell
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        cell = [tableView dequeueReusableCellWithIdentifier:"CustomCell"];
    });
    DataModel *model = self.dataArray[(NSUInteger) indexPath.row];
    [cell makeupData:model];

    if (model.cellHeight <= 0) {
        //使用systemLayoutSizeFittingSize獲取高度
        model.cellHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 1;
    }
    return model.cellHeight;
}

在 iOS 8 中cell 如果有一個確定的寬度/高度,autolayout 會自動根據 cell 中的內容計算出對應的高度/寬度。(目前不需要適配iOS7了,iOS11之後iOS8的適配也快拋棄了)

要讓 table view 的 cell 自適應內容,有幾個要點:

  1. 設置的 AutoLayout 約束必須讓 cell 的 contentView 知道如何自動延展。關鍵點是 contentView 的 4 個邊都要設置連接到內容的約束,並且內容是會動態改變尺寸的。

  2. UITableView 的 rowHeight 的值要設置爲 UITableViewAutomaticDimension

  3. 實現tableView.estimatedRowHeight屬性或者 estimatedHeightForRowAtIndexPath代理。

//需要設置的兩句代碼:一點計算 cell 高度的代碼都沒有!!連heightForRowAtIndexPath都不用實現
 _tableView.estimatedRowHeight = 80;
_tableView.rowHeight = UITableViewAutomaticDimension;

UITextView 在Cell中的高度自適應

需要textView高度自適應的需求時常表現爲—UITextView嵌套在Cell中

//  TextViewCell.m
//cell初始化
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self.contentView addSubview:self.textView];
         __weak typeof(self) weakSelf = self;
        [self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(weakSelf.contentView);
        }];
    }
    return self;
}

-(UITextView *)textView
{
    if (!_textView) {
        _textView = [[UITextView alloc]init];
        _textView.backgroundColor = [UIColor greenColor];
        _textView.font = [UIFont systemFontOfSize:20];
        //scrollEnabled 必須設置爲NO,否則sizeToFit適配不了
        _textView.scrollEnabled = NO;
        _textView.delegate = self;
    }
    return _textView;
}

//實現變高的關鍵所在
-(void)textViewDidChange:(UITextView *)textView
{
    [textView sizeToFit];
    UITableView *tableView = [self tableView];
    [tableView beginUpdates];
    [tableView endUpdates];
}

- (UITableView *)tableView
{
    UIView *tableView = self.superview;

    while (![tableView isKindOfClass:[UITableView class]] && tableView) {
        tableView = tableView.superview;
    }

    return (UITableView *)tableView;
}
//tableView的代碼
-(UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain];
        _tableView.delegate = self;
        _tableView.dataSource = self;

        [_tableView registerClass:[TextViewCell class] forCellReuseIdentifier:@"TextViewCell"];

//自適應cell需要的代碼
        _tableView.estimatedRowHeight = 40;
        _tableView.rowHeight = UITableViewAutomaticDimension;

    }
    return _tableView;
}

UICollectionViewCell的自適應

在 collection view 中也能讓 cell 自適應內容大小,如果 UICollectionView 的 layout 是一個 UICollectionViewFlowLayout,只需要將 layout.itemSize = … 改成 layout.estimatedItemSize = …。 只要設置了 layout 的 estimatedItemSize,collection view 就會根據 cell 裏面的 autolayout 約束去確定cell 的大小

原理:

  1. collection view 根據 layout 的 estimatedItemSize 算出估計的 contentSize,有了 contentSize collection view 就開始顯示

  2. collection view 在顯示的過程中,即將被顯示的 cell 根據 autolayout 的約束算出自適應內容的 size

  3. layout 從 collection view 裏獲取更新過的 size attribute

  4. layout 返回最終的 size attribute 給 collection view

  5. collection 使用這個最終的 size attribute 展示 cell

//只需要實現估算高度,cell會根據其subviews自動獲取大小。
//也就是說cell的subviews需要有足夠的約束信息推斷出cell的size

layout.estimatedItemSize = CGSizeMake(SCREEN_WIDTH/2 , 150);

UIScrollView的自適應

UIScrollView也可以自適應,自適應UIScrollView就不需要我們再計算contentSize了。
但是要注意的是:UIScrollView的contentSize是根據它的subView來計算的,也就是其subViews自身必須能夠確定大小。

UIView *container = [UIView new];
[scrollView addSubview:container];
[container mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    //這裏的寬度的意思是:contentSize的寬固定,高度變化,豎直方向滑動
    make.width.equalTo(scrollView);
}];

總結:

AutoLayout 已經是勢在必行了,曾經它增加了代碼量,使很多人還停留在frame不捨得轉過來,現在呢,它可以極大的方便開發者,還可以省很多代碼。只要多加練習,對於iOS的佈局就不會再那麼恐怖了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章