1

我正在尝试创建一个动态大小的表格视图单元格。我已经阅读了每一个 SO 问题、网站、文章和示例 Github 项目,并且无法获得我想要的没有错误的布局(以当前的形式,没有错误,但最终结果如上图所示) .

我有一个包含多个部分的表格。第一部分有一个动态调整大小的单元格。我的目标是正确无误地显示此单元格。以下是细胞可能具有的两种不同的视觉状态:

这是单元格的所需外观,底部有一条消息: 带有动态大小消息的单元格

这是完全没有消息的单元格的理想外观:

完全没有消息的单元格

对于下面显示的代码,结果如下:

在此处输入图像描述

这是 TableViewController:

//
// The TableViewController
//

#import <Masonry.h>
#import "CustomCell.h"
#import "MyViewController.h"

@interface MyViewController()

@property (retain, nonatomic) CheckoutHeaderView *headerView;
@property (retain, nonatomic) CustomCell *customCell;

@end


@implementation MyViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView = [[UITableView alloc] init];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    self.tableView.allowsSelection = NO; 
    [self.tableView registerClass:[CustomCell class] forCellReuseIdentifier:@"customCell"];

    [self.view addSubview:self.headerView];
    [self.view addSubview:self.tableView];

    [self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.view);
        make.left.equalTo(self.view);
        make.right.equalTo(self.view);
    }]; 

    [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.headerView.mas_bottom);
        make.left.equalTo(self.view);
        make.right.equalTo(self.view);
        make.bottom.equalTo(self.view);
    }]; 

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    return self.customerCell;
}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    static dispatch_once_t onceToken;
    static CustomCell *customCell;
    dispatch_once(&onceToken, ^{
        customCell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:@"customCell"];
        self.customCell = customerCell;
    }); 

    self.customCell.model = self.model;

    return [self calculateHeightForConfiguredSizingCell:self.customCell];
}

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

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 1;
}

- (CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell {
    [sizingCell setNeedsUpdateConstraints];
    [sizingCell updateConstraintsIfNeeded];

    sizingCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(self.tableView.bounds));

    [sizingCell setNeedsLayout];
    [sizingCell layoutIfNeeded];

    CGFloat height = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    height += 1.0f;

    return height;
}

@end

这是单元格类:

#import "CustomCell.h"
#import <Masonry.h>
#import "Label.h"
#import "Order.h"
#import "Helper.h"
#import "Theme.h"

@interface CustomCell()

@property (assign, nonatomic) BOOL didSetupConstraints;

@property (retain, nonatomic) Label *dateOneLabel;
@property (retain, nonatomic) Label *dateTwoToLabel;
@property (retain, nonatomic) Label *messageLabel;

@property (retain, nonatomic) Label *dateOneValue;
@property (retain, nonatomic) Label *dateTwoToValue;
@property (retain, nonatomic) Label *messageText;

@property (retain, nonatomic) NSMutableArray *messageConstraints;
@property (retain, nonatomic) MASConstraint *pinBottomOfDateTwoLabelToBottomOfContentViewConstraint;

@end

@implementation CustomCell

- (NSMutableArray *)messageConstraints {
    return _messageConstraints ? _messageConstraints : [@[] mutableCopy];
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self setup];
    }   
    return self;
}

- (void)awakeFromNib {
    [self setup];
}

- (void) setup {

    self.didSetupConstraints = NO; 

    self.dateOneLabel = [UILabel new];
    self.dateOneLabel.text = @"Date One";

    self.dateTwoLabel = [UILabel new];
    self.dateTwoLabel.text = @"Date Two";

    self.messageLabel = [UILabel new];
    self.messageLabel.text = @"Message";

    self.dateOneValue = [UILabel new];
    self.dateTwoToValue = [UILabel new];

    // The actual message text label that spans numerous lines.
    self.messageText = [UILabel new];
    self.messageText.numberOfLines = 0;
    self.messageText.adjustsFontSizeToWidth = NO; 


    [self.contentView addSubview:self.dateOneLabel];
    [self.contentView addSubview:self.dateTwoToLabel];
    [self.contentView addSubview:self.messageLabel];
    [self.contentView addSubview:self.dateOneValue];
    [self.contentView addSubview:self.dateTwoToValue];
    [self.contentView addSubview:self.messageText];
}

- (void)layoutSubviews {
    [super layoutSubviews];

    [self.contentView setNeedsLayout];
    [self.contentView layoutIfNeeded];

    self.messageText.preferredMaxLayoutWidth = CGRectGetWidth(self.messageText.frame);
}

- (void)updateConstraints {

    if (!self.didSetupConstraints) {

        __weak typeof (self.contentView) contentView = self.contentView;

        // Topmost label, pinned to left side of cell.
        [self.dateOneLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(contentView).with.offset(14);
            make.right.lessThanOrEqualTo(self.dateOneValue.mas_left).with.offset(-20);
            make.top.equalTo(contentView).with.offset(14);
        }]; 

        // Second label, pinned to left side of cell and below first label.
        [self.dateTwoToLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.dateOneLabel);
            make.top.equalTo(self.dateOneLabel.mas_bottom).with.offset(6);
            make.right.lessThanOrEqualTo(self.dateTwoToValue.mas_left).with.offset(-20);
        }]; 

        // First date value, pinned to right of cell and baseline of its label.
        [self.dateOneValue mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.right.equalTo(contentView).with.offset(-14).priorityHigh();
            make.baseline.equalTo(self.dateOneLabel);
        }]; 

        // Second date value, pinned to right of cell and baseline of its label.
        [self.dateTwoToValue mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.right.equalTo(self.dateOneValue);
            make.baseline.equalTo(self.dateTwoToLabel);
        }]; 

        self.didSetupConstraints = YES;
    }   

    [super updateConstraints];
}

- (void)uninstallMessageConstraints {
    [self.pinBottomOfDateTwoLabelToBottomOfContentViewConstraint uninstall];
    for (MASConstraint *constraint in self.messageConstraints) {
        [constraint uninstall];
    }   
    [self.contentView mas_remakeConstraints:^(MASConstraintMaker *make) {
        self.pinBottomOfDateTwoLabelToBottomOfContentViewConstraint = make.bottom.equalTo(self.dateTwoToLabel).with.offset(14);
    }]; 
}

- (void)installMessageConstraints {

    __weak typeof (self.contentView) contentView = self.contentView;

    [self.pinBottomOfDateTwoLabelToBottomOfContentViewConstraint uninstall];

    // Below, add constraints of `self.messageConstraints` into an array so
    // they can be removed later.

    [self.messageConstraints addObjectsFromArray:[self.messageLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.dateOneLabel);
        make.top.equalTo(self.dateTwoToLabel.mas_bottom).with.offset(6);
    }]];

    self.messageConstraints = [[self.messageText mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.messageLabel);
        make.top.equalTo(self.messageLabel.mas_bottom).with.offset(6);
        make.right.equalTo(contentView).with.offset(-14);
    }] mutableCopy];

    [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        self.pinBottomOfDateTwoLabelToBottomOfContentViewConstraint = make.bottom.equalTo(self.messageText).with.offset(14);
    }]; 

}


- (void)setModel:(MyModel *)model {
    if (!model.message || model.message.length < 1) {
        [self uninstallMessageConstraints];
        self.messageText.text = @"";
        [self.messageLabel removeFromSuperview];
        [self.messageText removeFromSuperview];
    } else {
        self.messageText.text = model.message;
        if (![self.contentView.subviews containsObject:self.messageLabel]) {
            [self.contentView addSubview:self.messageLabel];
        }   
        if (![self.contentView.subviews containsObject:self.messageText]) {
            [self.contentView addSubview:self.messageText];
        }   
        [self installMessageConstraints];
    }   

    self.dateOneValue.text = model.dateOne;
    self.dateTwoValue.text = model.dateTwo;

    [self.contentView setNeedsDisplay];
    [self.contentView setNeedsLayout];
}

@end

我已经对此进行了两天的修改,在某些时候,它看起来符合预期,但出现了自动布局错误。我不知道我的错误在哪里,所以我的一般问题是:我的代码有什么问题,需要改变什么才能产生正确的结果?

非常感谢。

4

1 回答 1

0

我认为您需要添加self.messageText.lineBreakMode = NSLineBreakByWordWrapping以强制将其添加到多行。

于 2015-05-22T22:21:53.333 回答