UITableViewCell 子视图不遵守自动布局约束

Posted

技术标签:

【中文标题】UITableViewCell 子视图不遵守自动布局约束【英文标题】:UITableViewCell subviews are not honoring the Autolayout constraints 【发布时间】:2015-02-04 09:28:20 【问题描述】:

我正在绘制一个相当简单的自定义 UITableViewCell——左侧是缩略图,右侧是名称和链接标签。我希望我的名称和链接标签是单行的,如果文本超过单元格的宽度,则在尾部截断。我很确定我正确地添加了我的约束,但我的名字和链接标签不会尊重它们。

这是运行 ios 8 的 iPhone 4S 上的单元格的样子:

在我的代码中,我为超级视图(单元格的 contentView)添加了名称和链接标签的 10 点尾随约束,但请注意,即使在横向,iOS 似乎也不遵守约束.

谁能告诉我我做错了什么?这是我的整个单元格的代码。我正在以编程方式创建视图,并且在表格视图单元格的初始化程序中有自动布局约束。

#import "PopularWikiCell.h"

// Models
#import "Wiki.h"

// Pods
#import "UIImageView+AFNetworking.h"

// Constants
static const CGFloat kPadding = 10;
static const CGFloat kImageSize = 100;
const CGFloat kPopularWikiCellHeight = kImageSize + kPadding * 2;

@interface PopularWikiCell ()

@property (nonatomic, strong) UIImageView *thumbnailView;
@property (nonatomic, strong) UILabel *nameLabel;
@property (nonatomic, strong) UILabel *linkLabel;

@end

@implementation PopularWikiCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) 
        // Initialise the subviews.
        _thumbnailView = [[UIImageView alloc] init];
        _thumbnailView.contentMode = UIViewContentModeScaleAspectFill;
        _thumbnailView.clipsToBounds = YES;

        _nameLabel = [[UILabel alloc] init];
        _nameLabel.backgroundColor = [UIColor blueColor];
        _nameLabel.numberOfLines = 1;
        _nameLabel.lineBreakMode = NSLineBreakByTruncatingTail;
        _nameLabel.text = @"Name";

        _linkLabel = [[UILabel alloc] init];
        _linkLabel.backgroundColor = [UIColor redColor];
        _linkLabel.text = @"Link";
        _linkLabel.numberOfLines = 1;
        _linkLabel.lineBreakMode = NSLineBreakByTruncatingTail;

        // Add the subviews.
        [self.contentView addSubview:_thumbnailView];
        [self.contentView addSubview:_nameLabel];
        [self.contentView addSubview:_linkLabel];

        _thumbnailView.translatesAutoresizingMaskIntoConstraints = NO;
        _nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
        _linkLabel.translatesAutoresizingMaskIntoConstraints = NO;
        self.contentView.translatesAutoresizingMaskIntoConstraints = NO;

        // Add the layout constraints.

        NSDictionary *metrics = @@"kPadding" : @(kPadding),
                                  @"kImageSize" : @(kImageSize);
        NSDictionary *views = @@"thumbnailView" : _thumbnailView,
                                @"nameLabel" : _nameLabel,
                                @"linkLabel" : _linkLabel;

        NSArray *constraints = @[@"H:|-kPadding-[thumbnailView(kImageSize)]-kPadding-[nameLabel]-kPadding-|",
                                 @"H:[thumbnailView]-kPadding-[linkLabel]-kPadding-|",
                                 @"V:|-kPadding-[nameLabel]-0-[linkLabel]",
                                 @"V:|-kPadding-[thumbnailView(kImageSize)]"];

        [self.contentView addConstraintsFromVisualFormatStrings:constraints
                                                        options:0
                                                        metrics:metrics
                                                          views:views];
    
    return self;


- (void)setWiki:(Wiki *)wiki

    _wiki = wiki;

    self.thumbnailView.image = nil;
    self.thumbnailView.backgroundColor = [UIColor darkGrayColor];
    __weak typeof(self) weakSelf = self;
    [self.thumbnailView setImageWithURLRequest:[NSURLRequest requestWithURL:wiki.thumbnailURL]
                              placeholderImage:nil
                                       success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) 
                                           __strong typeof(self) strongSelf = weakSelf;
                                           strongSelf.thumbnailView.image = image;
                                           strongSelf.thumbnailView.backgroundColor = [UIColor whiteColor];
                                       
                                       failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) 

                                       ];

    self.nameLabel.text = wiki.name;
    self.linkLabel.text = wiki.URL;

    [self.contentView setNeedsLayout];


- (void)setSelected:(BOOL)selected animated:(BOOL)animated

    [super setSelected:selected animated:animated];

    // Selection removes all background colors so re-set it.
    [self resetSubviewBackgroundColors];

    [self.contentView setNeedsLayout];


- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated

    [super setHighlighted:highlighted animated:animated];

    // Highlighing removes all background colors so re-set it.
    [self resetSubviewBackgroundColors];

    [self.contentView setNeedsLayout];


- (void)resetSubviewBackgroundColors

    if (self.thumbnailView.image) 
        self.thumbnailView.backgroundColor = [UIColor whiteColor];
     else 
        self.thumbnailView.backgroundColor = [UIColor darkGrayColor];
    


@end

【问题讨论】:

你是在 IB 中添加约束吗? @YuviGr 嗨,我不是。我所有的视图和子视图都是在这个应用程序中以编程方式创建的。 那你要计算字符串的长度,我贴个答案 【参考方案1】:

问题隐藏在

self.contentView.translatesAutoresizingMaskIntoConstraints = NO;

删除此代码可以解决您的问题。

如果您不希望 将自动调整掩码转换为约束 - 为 cell.contentView 设置您想要的约束。

【讨论】:

【参考方案2】:

在你的 cellForRow: 方法中确保你正在调用:

cell = [tableView dequeueReusableCellWithReuseIdentifier:@"" forIndexPath:(IndexPath *)

调用它会返回一个正确大小的单元格(对于自动布局很重要)

如果这不能解决问题,请在您的单元内实现:

-(void)layoutSubview 
    [super layoutSubviews];

    [self layoutIfNeeded];

【讨论】:

【参考方案3】:

首先我强烈推荐使用自动布局,它解决了很多尺寸问题和很多计算

但是,如果您没有设置约束,那么您必须计算字符串的长度以适合您想要的标签的宽度

NSString *string = @"this is a very long string to fit into a UILabel";
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 50, 150, 20)];
UIFont *font = [UIFont fontWithName:@"Helvetica Neue" size:15.0];
label.font = font;
label.text = string;
CGSize stringSize = [string sizeWithAttributes:@NSFontAttributeName : font];

// check if the string is wider then the label
if (stringSize.width > label.bounds.size.width) 
    NSString *newString = [string substringWithRange:NSMakeRange(0, string.length/2)]; <----  i just divided the string into two -----
    // check if the newString fits the label
    // if not the divide again

    label.text = newString;
else
    label.text = string;

[self.view addSubview:label];

就像我在代码中写的那样,我只是将字符串分成两个字符串。如果您有一个很长的字符串,这可能不起作用,因此您需要继续检查字符串是否适合标签。

您可以使用:

[NSString stringWithFormat:@"%@...", [string substringToIndex:20]];

在字符串末尾添加“...”

【讨论】:

【参考方案4】:

我无法加载你的图片,所以我不确定你遇到了什么问题。

我看到这段代码,有错别字吗?

NSArray *constraints = 
@[
@"H:|-kPadding-[thumbnailView(kImageSize)]-kPadding-[nameLabel]-kPadding-|",
@"H:[thumbnailView]-kPadding-[linkLabel]-kPadding-|",  //this line you forgot the left edge
@"V:|-kPadding-[nameLabel]-0-[linkLabel]",
@"V:|-kPadding-[thumbnailView(kImageSize)]"
];

【讨论】:

【参考方案5】:

您好,您可以在自定义 UITableViewCell 中尝试此操作,设置内容视图的框架或标签或使用这些的任何元素:-

在声明中:-

GRect usableSpace;
CGFloat usableWidth, usableHeight;

实施中:-

usableSpace = [[UIScreen mainScreen] applicationFrame];
usableWidth = usableSpace.size.width;
usableHeight = usableSpace.size.height;

然后使用这些宽度和高度设置框架

【讨论】:

【参考方案6】:

即使我的视图看起来不错,我得到的宽度也不正确,底层的 CGRect 是错误的。

当使用CAShapeLayer 为我的单元格添加边框时,这一点变得很明显。

我通过在contentView 上调用layoutIfNeeded() 来修复它

 override func layoutSubviews() 
     super.layoutSubviews()
     contentView.layoutIfNeeded()

【讨论】:

以上是关于UITableViewCell 子视图不遵守自动布局约束的主要内容,如果未能解决你的问题,请参考以下文章

自动调整子类 UITableViewCell 子视图的大小

添加子视图后,UITableViewCell contentView 框架大小会自动增加吗

以编程方式自动调整包含多个子视图的 UITableViewCell

自定义 UIView(.xib) 在 UITableViewCell 中添加为子视图后自动更改框架

如何设置我的 UITableViewCell 子类的子视图以使用自动调整大小的蒙版?

何时何地根据实际宽度更新 UITableViewCell 子视图的约束