iOS 以编程方式为表格视图单元格内容创建 NSLayoutConstraint

Posted

技术标签:

【中文标题】iOS 以编程方式为表格视图单元格内容创建 NSLayoutConstraint【英文标题】:iOS create NSLayoutConstraint programmatically for table view cell content 【发布时间】:2013-12-01 21:08:12 【问题描述】:

我想在 cellForRowAtIndexPath 中添加一些视图到我的单元格内容视图并为它们添加约束,但没有任何效果。我有这样的事情:

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:imageView
                                  attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:cell.contentView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:10.0f];

[cell.contentView addConstraint:constraint];

我应该怎么做?

【问题讨论】:

您是否使用手动添加到单元格的图像视图来执行此操作?在添加自己的控件时,我建议不要使用现有 imageView 属性的名称(例如,imageViewtextLabeldetailTextLabel)。或者您是否尝试在现有的 imageView 上执行此操作,我也不建议这样做。 不,这只是示例名称,我为图像视图使用了另一个名称。 【参考方案1】:

几个观察:

    您创建的这个特定约束是正确的。显然,您不能只设置左侧约束,而是需要指定将明确定义单元格子视图的frame 的所有约束。例如,不仅要定义左侧(或前导)约束,还要定义顶部、底部和宽度约束。或者定义左约束加上宽度和高度约束,并指定垂直 y 约束。有很多不同的方法来做到这一点,但关键是您必须添加所有约束,这些约束将明确定义所有子视图的frame

    例如,您可能有以下内容:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    
        static NSString *cellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    
        UIImageView *customImageView;
        UILabel *customLabel;
    
        if (cell == nil) 
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    
            customImageView = [[UIImageView alloc] init];
            customImageView.translatesAutoresizingMaskIntoConstraints = NO;
            customImageView.tag = IMAGEVIEWTAG;
            [cell.contentView addSubview:customImageView];
    
            [cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:customImageView
                                                                         attribute:NSLayoutAttributeLeading
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:cell.contentView
                                                                         attribute:NSLayoutAttributeLeft
                                                                        multiplier:1.0
                                                                          constant:25.0]];
    
            [cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:customImageView
                                                                         attribute:NSLayoutAttributeWidth
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:nil
                                                                         attribute:NSLayoutAttributeNotAnAttribute
                                                                        multiplier:1.0
                                                                          constant:30.0]];
    
            [cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:customImageView
                                                                         attribute:NSLayoutAttributeTop
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:cell.contentView
                                                                         attribute:NSLayoutAttributeTop
                                                                        multiplier:1.0
                                                                          constant:3.0]];
    
            [cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:customImageView
                                                                         attribute:NSLayoutAttributeBottom
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:cell.contentView
                                                                         attribute:NSLayoutAttributeBottom
                                                                        multiplier:1.0
                                                                          constant:-3.0]];
    
            customLabel = [[UILabel alloc] init];
            customLabel.translatesAutoresizingMaskIntoConstraints = NO;
            customLabel.tag = LABELTAG;
            [cell.contentView addSubview:customLabel];
    
            [cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:customLabel
                                                                         attribute:NSLayoutAttributeLeading
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:customImageView
                                                                         attribute:NSLayoutAttributeTrailing
                                                                        multiplier:1.0
                                                                          constant:10.0]];
    
            [cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:customLabel
                                                                         attribute:NSLayoutAttributeTrailing
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:cell.contentView
                                                                         attribute:NSLayoutAttributeTrailing
                                                                        multiplier:1.0
                                                                          constant:-10.0]];
    
            [cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:customLabel
                                                                         attribute:NSLayoutAttributeTop
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:cell.contentView
                                                                         attribute:NSLayoutAttributeTop
                                                                        multiplier:1.0
                                                                          constant:3.0]];
    
            [cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:customLabel
                                                                         attribute:NSLayoutAttributeBottom
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:cell.contentView
                                                                         attribute:NSLayoutAttributeBottom
                                                                        multiplier:1.0
                                                                          constant:-3.0]];
    
        
        else 
            customImageView = (id)[cell.contentView viewWithTag:IMAGEVIEWTAG];
            customLabel     = (id)[cell.contentView viewWithTag:LABELTAG];
        
    
        customImageView.image = ...;
        customLabel.text      = ...;
    
        return cell;
    
    

    显然,您会经常使用 UITableViewCell 子类来促进跟踪自定义控件的过程,但我想让示例保持简单。

    如果您不确定约束是否已明确定义,请运行应用程序并在呈现 UI 后暂停应用程序并在 (lldb) 提示符处输入以下内容:

    po [[UIWindow keyWindow] _autolayoutTrace]
    

    这将通知您是否有任何视图定义不明确(即是否缺少任何约束)。

    如果您想查看所有视图的frame 是什么,可以在(lldb) 提示符处输入以下内容:

    po [[UIWindow keyWindow] recursiveDescription]
    

    确保为所有子视图指定translatesAutoresizingMaskIntoConstraintsNO,就像我在上面的代码示例中所做的那样。

    虽然您可以使用constraintWithItem 定义约束,但人们通常会使用constraintsWithVisualFormat,因为您通常可以通过这种方式更简洁地定义约束。将上述代码示例与此代码示例进行对比:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    
        static NSString *cellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    
        UIImageView *customImageView;
        UILabel *customLabel;
    
        if (cell == nil) 
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    
            customImageView = [[UIImageView alloc] init];
            customImageView.translatesAutoresizingMaskIntoConstraints = NO;
            customImageView.tag = IMAGEVIEWTAG;
            [cell.contentView addSubview:customImageView];
    
            customLabel = [[UILabel alloc] init];
            customLabel.translatesAutoresizingMaskIntoConstraints = NO;
            customLabel.tag = LABELTAG;
            [cell.contentView addSubview:customLabel];
    
            NSDictionary *views = NSDictionaryOfVariableBindings(customImageView, customLabel);
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-25-[customImageView(30)]-[customLabel]|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-3-[customImageView]-3-|"                 options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-3-[customLabel]-3-|"                     options:0 metrics:nil views:views]];
        
        else 
            customImageView = (id)[cell.contentView viewWithTag:IMAGEVIEWTAG];
            customLabel     = (id)[cell.contentView viewWithTag:LABELTAG];
        
    
        customImageView.image = ...;
        customLabel.text      = ...;
    
        return cell;
    
    

【讨论】:

谢谢。这很有帮助。 ios9 开始,您可以使用 NSLayoutAnchor 类来编写“更简洁、更易于阅读”的视觉约束。 @Raiden996 - 是的,这比旧的 addConstraint/constraintWithItem 组合更好,但在这种情况下,我个人仍然会使用 VFL(在三行代码中添加八个约束)。 对于 textViews 如果你想让你的文本适合 textview 也添加这两行: [textView sizeToFit]; [keyTextView layoutIfNeeded];

以上是关于iOS 以编程方式为表格视图单元格内容创建 NSLayoutConstraint的主要内容,如果未能解决你的问题,请参考以下文章

iOS 8表格单元格内容不显示

如何以编程方式在单元格内创建文本字段或标签?

更新表格单元格内容的问题

以编程方式在 UITableViewCell 上显示删除按钮

表格视图高度之外的行的单元格内容发生变化(要查看此单元格,我们向下滚动)?

QML - 获取表格视图单元格内容