【问题标题】:How to know when a UITableViewCell is done with its AutoLayout pass如何知道 UITableViewCell 何时完成其 AutoLayout pass
【发布时间】:2014-03-05 04:10:45
【问题描述】:

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

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

服务器然后计算出返回哪个尺寸的图像以获得最佳结果。

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

我构建的自动布局填满了我的 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} //OK 现在看起来正确 - 可以调用 imageWithURL: now
  • {320,498} //可能是一个额外的用于计算单元格或表格视图 身高?

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

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

同样从上面的日志中,这会导致我的图像被设置 2 次,因为 layoutSubviews 被多次调用。

所以,希望有人可以帮助我正确确定这些调用的顺序,或者建议一种不同的方法来实现结果。

提前致谢。

【问题讨论】:

  • 我遇到了完全相同的问题。你最后是怎么解决的?

标签: ios uitableview autolayout


【解决方案1】:

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

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

强制布局

如果您知道您的视图约束已经安装并且您想要强制布局通过现在,您可以将视图的布局标记为脏并调用@ 987654324@:

[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
}

另外,请确保您为视网膜显示器请求双倍分辨率的图像。您可以使用UIScreen 上的scale 属性获取屏幕比例,然后将每个维度乘以它以进行一般处理。如果您不是为多个屏幕构建,只需使用[[UIScreen mainScreen] scale]

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 谢谢林赛。 viewDidLayoutSubviews 是(表)viewController 上的一个方法。我是否必须构建一些可见的女巫细胞映射,然后在那里更新 URL?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-01
    • 2011-04-05
    • 2021-04-25
    • 2020-02-13
    • 1970-01-01
    相关资源
    最近更新 更多