【问题标题】:Auto Layout on UITableView headerUITableView 标头上的自动布局
【发布时间】:2013-09-17 19:57:05
【问题描述】:

我一直在寻找关于如何将自动布局添加到 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;
}

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

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

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

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

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

正是因为那个错误,我才加了[headerView layoutSubviews]

对此有什么想法?提前致谢!

【问题讨论】:

    标签: ios autolayout


    【解决方案1】:

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

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

    后者是表格的标题。您设置视图,可能在您的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;
    }
    

    【讨论】:

    • 您能否提供代码 sn-ps 以说明如何进行?在这一点上,我仍然对如何对节标题或 tableview 标题进行约束感到困惑:-\。
    • 您以正常方式进行操作。但它们应该只是对其子视图的内部约束。在您形成它时,该视图不在您的界面中。如果它是节标题,它将自动调整大小以正确适应。如果是表头,你可以给它一个绝对高度,但它的宽度会被调整到合适的大小。
    • 不幸的是,它不起作用。 UITableViewHeaderFooterViewcontentView 已计算大小,您将在运行时收到 Unable to simultaneously satisfy constraints 警告。看起来虽然可以使用 AutoLayout 自动计算单元格高度,但对于节标题却不能这样做。刚刚在 iOS 8.1 上检查过。
    • @matt 如果您以一种应该拉伸标题以适应其内容的方式设置约束 - 它在 iOS 8 上不起作用。您将得到 Unable to simultaneously satisfy constraints 就像我说的那样。如果您将自定义子视图直接添加到标题视图而不是 contentView - 它会起作用。
    • @matt 这与喜欢与否无关 :-) 您很好地解释了如何将带有约束的自定义视图添加到标题视图。我同意这是这样做的正确方法。不幸的是,它会破坏 iOS 8 自动管理的约束。我只是展示了如何解决该问题以实现自动调整标题大小。您可以返回UITableViewAutomaticDimension,而不是在heightForHeaderInSection 中定义固定高度,它会自动调整标题高度。
    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      这是一个巧妙的解决方案:

      可选:initWithStyle:UITableViewStyleGrouped 防止浮动tableViewHeader

      制作两个属性,标签只是为了演示:

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

      在 viewDidLoad 中设置所有内容:

      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];
      

      在viewForHeaderInSection中:

      return self.headerView;
      

      在 heightForHeaderInSection:

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

      【讨论】:

      • 这种方法很棒。谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多