AutoLayout2、AutoLayout Cell 思路

 

整體思路:

  • 保存一個設置好約束的指定Cell類的對象     
  • 給Cell類對象填充須要顯示的全部數據項(UILabel值、UIImageView圖片...)
  • 而後在返回cell高度的回調函數中
  • 使用 [cell對象.cententView systemLayoutSizeFittingSize:UILayoutFitttingCompressSize] 讓ios sdk替咱們計算cell的真實高度。

 

第一步、定義全部cell必須實現的對象方法--》將傳入的實體對象設置給cell.contentView.subViews

#import <Foundation/Foundation.h>

@protocol ZSYAutoLayoutCellProtocol;

static CGFloat ZSYDynamicTableViewCellAccessoryWidth = 33;

//這個數組用來保存全部類型的自動佈局的Cell類的一個對象,用於後面計算cell高度
static NSMutableArray *cellArray;

//先傳出保存的cell對象,而後再用調用者返回設置了全部顯示數據的cell對象,用於計算cell高度須要
typedef id (^setupCellBlock)(id<ZSYAutoLayoutCellProtocol> cellToSetup);

@protocol ZSYAutoLayoutCellProtocol <NSObject>

//全部cell設置數據
- (void)setupDataItem:(id)data;

//計算cell高度
+ (CGSize)sizeForCellWithDefaultSize:(CGSize)defaultSize setupCellBlock:(setupCellBlock)block;

@end

 

第二步、寫一個BaseCell作一個默認實現接口

- (void)setupDataItem:(id)data {
    //這個方法子類cell重寫,將實體對象設置給cell.contentView.subviews
}

+ (CGSize)sizeForCellWithDefaultSize:(CGSize)defaultSize setupCellBlock:(setupCellBlock)block {
    __block UITableViewCell *cell = nil;
    
    //查看靜態數組內是否已經存在當前Cell類的一個對象
    [cellArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if ([obj isKindOfClass:[[self class] class]]) {
            cell = obj;
            *stop = YES;
        }
    }];
    
    //若是不存在,建立一個當前Cell類型的對象,並保存到數組。後續計算當前Cell類型對象的高度時,直接使用這個保存的Cell對象
    if (!cell) {
        cell = [[[self class] alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"XZHAutoLayoutCellIdentifier"];
        cell.frame = CGRectMake(0, 0, defaultSize.width, defaultSize.height);
        [cellArray addObject:cell];

    }
    
    //獲取到設置了屬性值的cell對象[1.先回傳出去 2.再接收Block的一個返回值cell對象]
    cell = block((id<ZSYAutoLayoutCellProtocol>) cell);
    
    //獲取到cell對象的 CGSize
//    [cell.contentView layoutIfNeeded];
    CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    
    size.width = MAX(defaultSize.width, size.width);
    size.height = size.height + 1.0f;
    
    return size;
}

 

第三步、編寫某個具體的Cell

// 實現接口定義的設置實體類對象的方法

- (void)setupDataItem:(id)data {
    if ([data isKindOfClass:[ZSYEntityModule class]]) {
        _entity = (ZSYEntityModule *)data;
        
        _titleLabel.text = _entity.title;
        [_contentImageView sd_setImageWithURL:[NSURL URLWithString:_entity.imageURL]
                             placeholderImage:[UIImage imageNamed:@"blankpage_image_Hi"]
                                      options:SDWebImageProgressiveDownload];
        
        //UILabel寫上這一句
        [_titleLabel layoutIfNeeded];
    }
}

 

//給Cell.contentView.subviews分別設置約束,使用VFL

- (void)initSubviews {
    
    self.backgroundColor = [UIColor whiteColor];
    self.accessoryType = UITableViewCellAccessoryNone;
    self.accessoryView = nil;
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    [self.contentView setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
    
    _titleLeftImageView = [[UIImageView alloc] init];
    _titleLeftImageView.image = [UIImage imageNamed:@"icon_title"];
    _titleLeftImageView.translatesAutoresizingMaskIntoConstraints = NO;
    _titleLeftImageView.contentMode = UIViewContentModeScaleAspectFill;
    
    _titleLabel = [[UILabel alloc] init];
    _titleLabel.numberOfLines = 0;
    _titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
    _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
    _titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-Bold" size:15];
    _titleLabel.textColor = [UIColor hex:@"#514647"];
    
    _contentImageView = [[UIImageView alloc] init];
    _contentImageView.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.contentView addSubview:_titleLeftImageView];
    [self.contentView addSubview:_titleLabel];
    [self.contentView addSubview:_contentImageView];
    
    NSDictionary *viewDict = NSDictionaryOfVariableBindings(_titleLeftImageView, _titleLabel, _contentImageView);
    
    NSDictionary *metricDict = @{@"sideBuffer1" : @16,
                                 @"sideBuffer2" : @10,
                                 @"vertical_top_Buffer" : @12,
                                 @"vertical_middle_Buffer" : @16,
                                 @"vertical_bottom_Buffer" : @12.5,
                                 @"labelImageSizeWith" : @(_titleLeftImageView.image.size.width),
                                 @"labelImageSizeHeight" : @(_titleLeftImageView.image.size.height),
                                 @"contentImageSizeHeight" : @181};
    
    NSString *vfl = @"H:|-sideBuffer1-[_titleLeftImageView(labelImageSizeWith)]-5-[_titleLabel]-sideBuffer2-|";
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl options:0 metrics:metricDict views:viewDict]];
    
    vfl = @"H:|-sideBuffer2-[_contentImageView]-sideBuffer2-|";
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl options:0 metrics:metricDict views:viewDict]];
 
    vfl = @"V:|-vertical_top_Buffer-[_titleLeftImageView]";
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl options:0 metrics:metricDict views:viewDict]];
    
    vfl = @"V:|-vertical_top_Buffer-[_titleLabel]-vertical_middle_Buffer-[_contentImageView(contentImageSizeHeight)]-vertical_bottom_Buffer-|";
    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl options:0 metrics:metricDict views:viewDict]];
    
//    vfl = @"V:[_contentImageView(contentImageSizeHeight)]-vertical_bottom_Buffer-|";
//    [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl options:0 metrics:metricDict views:viewDict]];
    
//    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleLeftImageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.titleLabel attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
    
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleLeftImageView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.titleLabel attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
    
//    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleLeftImageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.titleLabel attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];
    
    [self.titleLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
    [self.titleLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
    
    //獲取每一個cell重寫後,本身的默認size
    CGSize defaultSize = [[self class] defaultCellSize];

    //注意: 全部UILabel若是須要高度動態改變,必定要設置preferredMaxLayoutWidth最大寬度
    self.titleLabel.preferredMaxLayoutWidth = defaultSize.width - [metricDict[@"sideBuffer1"] floatValue] -[metricDict[@"labelImageSizeWith"] integerValue] - 5 - [metricDict[@"sideBuffer2"] integerValue];

}

 

第四步、tableview回調代理函數cell高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    if (![[self cellClass] isDynamic]) {
        return [self cellDefaultHeight];
    }
        
    __weak typeof(self) weakSelf = self;
    
    //默認 size
    CGSize defaultSize = [[self cellClass] defaultCellSize];
    
    //計算後自適應的 size
    CGSize cellSize = [[self cellClass] sizeForCellWithDefaultSize:defaultSize
                                                    setupCellBlock:^id(id<ZSYAutoLayoutCellProtocol> cellToSetup)
    {
        NSArray *dataList = [weakSelf dataSource];
        if ([self sectionCount] == 1) {//一維數組
            [cellToSetup setupDataItem:dataList[[indexPath row]]];
        } else {//二惟數組
            NSArray *sectionArray = dataList[indexPath.section];
            id obj = sectionArray[indexPath.row];
            [cellToSetup setupDataItem:obj];
        }
        return cellToSetup;
    }];
    
    return cellSize.height;

}
相關文章
相關標籤/搜索