如何知道UITableViewCell何时完成其AutoLayout传递

时间:2014-02-28 09:31:33

标签: ios uitableview autolayout

我提供的单元格包含一些文字和图片的网址。 使用imageFromURL:方法显示图像的ImageView是一个自定义类,它在内部查看自己的大小并向URL附加查询,如:

.com/img.png?ver=200&hor=500

服务器然后确定要返回的大小图像以获得最佳结果。

这意味着我需要AutoLayout在除了文本之外的任何内容之前布局imageView。在我保证imageView具有其最终大小后,我调用imageWithURL:方法。

我构建的autolayout填充了我的textLabel,由于单元格高度是固定的,因此它决定了图像的剩余部分。 (一些抗压缩性,最小尺寸等等 - 这一切都有效,我从下面的代码中省略了它。)

- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    /*
     stuff that goes into making the cell ready
     .
     .
     .
     */
    [self setNeedsUpdateConstraints];

    return self;
}

- (void)updateConstraints
{
    /*
     first set the different constraints
     .
     .
     .
     then call super
     */
     [super updateConstraints];
}

- (void) updateCellWithText:(NSString*) text andImageURL:(NSURL*) imgURL
{
    self.textLabel.text = text;
    [self.imageView setImageWithURL:imgURL];
    //calling setNeedsUpdateConstraints here won't help much as there is still not a correct size
}

- (void) layoutSubviews
{
    [super layoutSubviews];
    NSLog(@"%@", NSStringFromCGSize(self.imageView.frame.size));
}

我从layoutSubviews:登录的是:

  • {0,0} //第一次
  • {320,498} //现在看起来正确 - 可以调用imageWithURL:now
  • {320,498} //可能是计算单元格或tableview的一个额外内容 高度?

我的目标是弄清楚我们何时完成布局,并且可以使用正确大小的imageView调用我的setImageWithURL:。 layoutSubviews似乎是唯一可以嵌入此信息的地方 - 但我真的觉得在将这样的代码添加到layoutSubviews并将我的数据更新混合到我的布局代码中时感到很不舒服:

if (_imageView.frame.size.width == 0)
    [_imageView setImageWithURL:_propertyWithURL];

同样来自上面的日志记录会导致我的图像被设置2次,因为layoutSubviews被多次调用。

所以,希望有人可以帮助我正确地获得这些电话的顺序,或建议采用不同的方法来实现结果。

提前致谢。

2 个答案:

答案 0 :(得分:2)

您不需要在init中显式调用setNeedsUpdateConstraints。此可能导致双重布局调用。还有一个非常好的机会layoutSubviews将被频繁调用,因为这是在updateConstraints之后调用的方法,以便除了标记布局的任何其他操作之外还设置每个视图的帧脏了。但是,这将是检查自动布局传递结果的帧的正确位置,因为这是您感兴趣的内容。

有几种方法可以解决这个问题:

强制布局

如果知道已经安装了视图约束,并且您想强制布局立即传递,则可以将视图的布局标记为脏并调用{ {1}}:

layoutIfNeeded

谨慎使用此方法,因为它基本上是在您告诉系统时强制系统进行布局。通常,您希望允许系统根据需要进行布局,因为使用自动布局布局可能很昂贵。

仅更改时更新图像

另一种方法是让系统在正常情况下处理布局,同时仍然在[self setNeedLayout]; [self layoutIfNeeded]; CGSize imageSize = self.imageView.bounds.size; 中检查图像视图的帧,但是如果图像的大小与您的图像大小不同,则仅获取新图像已经开始了。在这种情况下,这将为您提供您正在寻找的结果,因为图像视图的大小在后两次传递中是相同的。这也允许图像视图更改大小并仍然获得更新的图像:

layoutSubviews

另外 - 确保您要求双倍分辨率的图像用于视网膜显示。您可以使用if (CGSizeEqualToSize(self.imageView.bounds.size, self.lastImageViewSize) == NO) { //fetch new image from server } 上的scale属性获取屏幕比例,并将每个维度乘以该值来统一处理它。如果您不是为多个屏幕构建,请使用UIScreen

答案 1 :(得分:1)

首先,使用viewDidLayoutSubviews检测视图何时完成布局子视图。

其次,有时甚至viewDidLayoutSubviews会被多次自动调用。如果你想确保你只设置一次图像,也许可以添加一个类变量,例如。 bool viewLaidout;,将其初始化为NO中的viewDidLoad,仅在viewDidLayoutSubviews viewLaidout == NO中设置图片,然后在viewDidLayoutSubviews的第一遍中,设置图片并将viewLaidout设置为YES,例如:

bool viewLaidout;

- (void)viewDidLoad {
    viewLaidout = NO;
}

- (void)viewDidLayoutSubviews {
    if (viewLaidout == NO) {
        [_imageView setImageWithURL:_propertyWithURL];
        viewLaidout = YES;
    }
}