UITableView 标头上的自动布局



我一直在寻找有关如何将自动布局添加到UITableView的明确答案。 到目前为止,我的代码如下所示:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    UINib *nib = [UINib nibWithNibName:@"HomeHeaderView" bundle:nil];
    UIView *headerView = (UIView *)[nib instantiateWithOwner:self options:nil][0];
    [headerView.layer setCornerRadius:6.0];
    [headerView setTranslatesAutoresizingMaskIntoConstraints:NO];
//    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(headerView);
//    NSMutableArray *headerConstraints = [[NSMutableArray alloc] init];
//    [headerConstraints addObject:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[headerView]-|" options:0 metrics:nil views:viewsDictionary]];
//        [headerConstraints addObject:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[headerView]-|" options:0 metrics:nil views:viewsDictionary]];
//    [self.actionsTableView addConstraints:headerConstraints];
//    [self.view addSubview:headerView];
    tableView.tableHeaderView = headerView;
    [headerView layoutSubviews];
    NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
    NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
    NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1 constant:300];
    NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1 constant:90];
    [self.view addConstraints:@[centerX, centerY, width, height]];
    return headerView;
}

我基本上有一个用于标题视图的笔尖文件,我想在我的 UITableViewHead 中居中。 我希望它在纵向和横向上相应地增长和缩小。 老实说,我不确定我是否正确设置了约束。 我不确定我的toItem应该是视图控制器的视图,还是表视图本身。

我也不知道我是否应该将标题视图作为子视图添加到视图控制器的视图或表视图本身。

或者,我不确定设置 tableView.tableHeaderView = headerView 是否足够。

我真的不知道这样的事情的最佳实践是什么。 我不确定这一切是否也可以在IB中完成。 目前,使用您看到的代码,我收到此错误:

'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super.'

正是由于这个错误,我添加了[headerView layoutSubviews]

对此有何看法? 提前感谢!

真正的问题是您将viewForHeaderInSection:与表的headerView混淆了。它们是无关的。

前者是的标题。从委托方法返回视图。

后者是的标题。您设置视图,可能是在您的viewDidLoad中。

约束以正常方式运行。但它们应该只是其子视图的内部约束。在您形成它时,视图不在您的界面中。而且它的大小和位置当时不取决于你。如果是节标题,它将自动调整大小以正确适合(根据表格的宽度和表格或委托对页眉高度的陈述)。如果是表头,您可以为其指定绝对高度,但其宽度将调整大小以正确适合。

下面是构造节标题的完整

示例,该节标题对其子视图具有内部约束。

- (UIView *)tableView:(UITableView *)tableView 
        viewForHeaderInSection:(NSInteger)section {
    UITableViewHeaderFooterView* h =
        [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"Header"];
    if (![h.tintColor isEqual: [UIColor redColor]]) {
        h.tintColor = [UIColor redColor];
        h.backgroundView = [UIView new];
        h.backgroundView.backgroundColor = [UIColor blackColor];
        UILabel* lab = [UILabel new];
        lab.tag = 1;
        lab.font = [UIFont fontWithName:@"Georgia-Bold" size:22];
        lab.textColor = [UIColor greenColor];
        lab.backgroundColor = [UIColor clearColor];
        [h.contentView addSubview:lab];
        UIImageView* v = [UIImageView new];
        v.tag = 2;
        v.backgroundColor = [UIColor blackColor];
        v.image = [UIImage imageNamed:@"us_flag_small.gif"];
        [h.contentView addSubview:v];
        lab.translatesAutoresizingMaskIntoConstraints = NO;
        v.translatesAutoresizingMaskIntoConstraints = NO;
        [h.contentView addConstraints:
         [NSLayoutConstraint 
          constraintsWithVisualFormat:@"H:|-5-[lab(25)]-10-[v(40)]"
          options:0 metrics:nil views:@{@"v":v, @"lab":lab}]];
        [h.contentView addConstraints:
         [NSLayoutConstraint 
          constraintsWithVisualFormat:@"V:|[v]|"
           options:0 metrics:nil views:@{@"v":v}]];
        [h.contentView addConstraints:
         [NSLayoutConstraint
          constraintsWithVisualFormat:@"V:|[lab]|"
           options:0 metrics:nil views:@{@"lab":lab}]];
    }
    UILabel* lab = (UILabel*)[h.contentView viewWithTag:1];
    lab.text = self.sectionNames[section];
    return h;
}

我发现 matt 提供的解决方案可能并不完美,因为他正在为UITableViewHeaderFooterView contentView添加自定义视图和约束。这总是会导致运行时自动布局警告:Unable to simultaneously satisfy constraints当我们想要动态标题高度时。

我不确定原因,但我们可以假设 iOS 为设置该视图的固定宽度和高度的contentView添加了一些额外的约束。运行时生成的警告告诉我们手动添加的约束不能满足这些约束,这很明显,因为我们的约束应该拉伸标题视图,以便子视图可以适合它。

解决方案非常简单 - 不要使用 UITableViewHeaderFooterViewcontentView,只需将您的子视图直接添加到 UITableViewHeaderFooterView 即可。我可以确认它在iOS 8.1上没有任何问题。如果要添加多个视图并更改标题的背景颜色,请考虑添加填充标题视图的UIView(由于AutoLayout约束),然后添加您希望拥有的所有子视图(我称之为customContentView)。这样我们就可以避免任何自动布局问题,并在 UITableView 中自动调整标题大小。

这是一个简洁的解决方案:

可选:initWithStyle:UITableViewStyle分组以防止浮动表视图标题

做两个属性,标签仅用于演示:

@property (nonatomic, strong, readwrite) UIView *headerView;
@property (nonatomic, strong, readwrite) UILabel *headerLabel;

在视图中设置所有内容DidLoad:

self.headerView = [[UIView alloc] initWithFrame:CGRectZero];
self.headerLabel = [[UILabel alloc] init];
self.headerLabel.text = @"Test";
self.headerLabel.numberOfLines = 0; //unlimited
self.headerLabel.textAlignment = NSTextAlignmentCenter;
self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; //always set this to NO when using AutoLayout
[self.headerView addSubview:self.headerLabel];
NSString *horizontalFormat = @"H:|-[headerLabel]-|";
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:horizontalFormat options:0 metrics:nil views:@{@"headerLabel":self.headerLabel}];
[self.headerView addConstraints:horizontalConstraints];
NSString *verticalFormat = @"V:|-[headerLabel]-|";
NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:verticalFormat options:0 metrics:nil views:@{@"headerLabel":self.headerLabel}];
[self.headerView addConstraints:verticalConstraints];

In viewForHeaderInSection:

return self.headerView;

在 heightForHeaderInSection:

self.headerLabel.preferredMaxLayoutWidth = tableView.bounds.size.width;
return [self.headerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

最新更新