【问题标题】:UIView's autolayout size reported from wrong size class the first time第一次从错误的大小类报告的 UIView 自动布局大小
【发布时间】:2016-09-10 02:51:27
【问题描述】:

我有一个 UITableViewController ,其中包含一些自定义单元格和每个单元格内的 UIView。我已经实现了控制器的 cellForRowAtIndexPath 来配置每个单元格中的 UIView。为此,我需要知道屏幕上 UIView 的宽度。由于我使用自动布局和大小类来根据设备方向自动更改 UIView 的大小,因此我实现了一种获取宽度运行时的附加方法。

问题是,当第一次显示表格视图时,即使我在横向使用设备时,我的代码也会从紧凑的宽度大小类报告 UIVIew 的宽度。系统按应有的方式呈现所有视图,但我获取宽度的代码不起作用。滚动可见的新单元格或改变方向将立即解决此问题。

我的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

            // ...

            CustomCell* cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];

            if (cell == nil) {
                NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
                cell = [nib firstObject];
            } else {

                // Clear custom content

                NSArray *viewsToRemove = [cell.histogramView subviews];
                for (UIView *v in viewsToRemove) {
                    [v removeFromSuperview];
                }
            }

            [cell setNeedsLayout];
            [cell layoutIfNeeded];

            int width = ((CustomView*)cell.customView).getWidth;
            NSLog(@"width = %d", width);

            // ...

}

然后:

@implementation CustomView

- (int)getWidth {
    [self setNeedsLayout];
    [self layoutIfNeeded];

    int width = self.frame.size.width;
    return width;
}

@end

编辑添加:

问题似乎是在第一次出现 tableview 时调用 cellForRowAtIndexPath 时,单元格没有发生自动布局。在创建单元格后立即使用 [cell setNeedsLayout] 和 [cell layoutIfNeeded] 强制它也不起作用。

看来我的问题根本原因是How to know the width of an UITableViewCell when using auto layout? 的潜在重复所以问题与这样一个事实有关,即当我的 CustomCell 从笔尖加载时,它将具有默认框架。应该做一些特殊的技巧来强制自动布局。但是,接受的答案不适用于最初不在可见区域的单元格。有没有人接受这个?

【问题讨论】:

  • 什么时候调用?确保它在 viewDidAppear 或更高版本中。如果在 viewWillAppear 或 viewDidLoad 中调用它,它还不会被调整大小。
  • 它是从 cellForRowAtIndexPath 调用的,因为它是配置单元格内容所需要的。调用在 sn-p 上可见。
  • 为什么不对单元格中的自定义内容使用大小类相关的自动布局?
  • 我是。但是我的 UIView 内容需要运行时计算,这就是为什么我需要知道自动布局后的宽度。我的代码不可靠,这是我提出问题的原因。

标签: ios objective-c uiview autolayout size-classes


【解决方案1】:

我建议尝试使用约束和比率而不是框架的实际宽度,因为正如 Marcus Adams 所说,只有在 viewDidAppear 之后,框架才会具有您实际寻找的值。

例如,如果您的单元格包含一个宽度为单元格宽度 1/3 的 UILabel,以及一个填充剩余空间的 UIImageView,您可以在它们和父视图之间设置约束。

你的逻辑可以这样改吗?

另一个建议是在 viewDidAppear 之后在您的表视图上调用 reloadData,但这绝对不是 UX 方面的好选择。

【讨论】:

  • 感谢您的回答。我的单元格中的 UIView 对其使用情节提要设置的宽度具有恒定的约束。纵向和横向模式(尺寸等级)将具有不同的宽度。我如何确定哪一个将用于在 cellForRowAtIndexPath 期间显示 UIView 以便正确配置 UIView 的内容,这依赖于维度运行时?
  • 您能否详细说明您希望纵向和横向视图的不同之处?我认为这可以通过对该大小类使用特定约束来解决,但我不确定我是否理解为什么在配置单元格时确实需要这些信息。
  • 所以假设我在 UITableViewCell 中有一个 UIView。对于一个尺寸等级(纵向),我希望 UIView 的宽度为 100。对于另一个尺寸等级(横向),我希望 UIView 的宽度为 150。我已经设置了它并且它可以工作。现在,我必须用无法使用自动布局配置的任何我想要的东西来填充 UIView。为了实现这一点,我需要一种方法来探测 UIView 的宽度运行时间。唯一的问题是,当单元格和 UIView 即将出现并从 nib 加载时,自动布局尚未发生,并且在 cellForRowAtIndexPath 期间报告了 nib 的默认宽度。
  • 一旦单元格和 UIView 重新出现在屏幕上(上下滚动它们),使用我的方法知道正确的宽度,所以我的代码几乎可以工作。
【解决方案2】:

我找到了正确的解决方案:

  1. 像原始问题一样创建一个自定义单元格。
  2. tableview: cellForRowAtIndexPath: 中设置cell.contentMode = UIViewContentModeRedraw
  3. 为自定义单元格实现layoutSubviews,如下所示:

    - (void)layoutSubviews { [super layoutSubviews]; NSLog(@"cell width == %f", self.bounds.size.width); }

这样您就可以访问屏幕上显示的单元格的大小。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-10
    • 2013-05-14
    • 1970-01-01
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多