在 iOS 7 中重新计算旋转时的子视图大小

Posted

技术标签:

【中文标题】在 iOS 7 中重新计算旋转时的子视图大小【英文标题】:Recalculating subview sizes on rotation in iOS 7 【发布时间】:2013-10-25 16:19:33 【问题描述】:

我调用了一个方法来计算我在自定义UITableViewCell 子类中拥有的一堆标签的大小,该子类位于UIPopoverController 中。当用户旋转设备时,我需要重新计算尺寸,然后重新绘制表格以使用新尺寸。我尝试检测旋转的每种方法要么被贬值,要么没有被调用,或者没有在正确的时间被调用。是否有一种方法可以在设备旋转时自动调用,我可以重新计算我的尺寸?


编辑:我尝试了什么以及为什么它不起作用:

shouldAutorotate - 没有被调用 - 显然已经贬值了。 layoutSubviews - 被调用,但如果我在这里尝试[self.tableView reloadData],我会陷入无限循环 NSNotificationCenter UIDeviceOrientationDidChangeNotification 的观察者 - 在我的控制器知道它是新尺寸之前被调用,所以我无法在这里重新计算我的尺寸 [self.tableView setNeedsDisplay] in layoutSubviews - 不会提示重新绘制表格。 didRotateFromInterfaceOrientation - 没有被调用 - 显然已经贬值了。

编辑 2:有关我正在尝试做的事情的更多详细信息

我正在尝试模仿“行和列”样式表,并排列标签以模仿列。当我重新计算大小时,我会遍历表格的所有行,然后遍历该行中的每个“列”。我得到每列的宽度,并跟踪每列的所有行中的最大宽度。然后我操纵宽度和字体大小之间的间距来获得它,这样如果任何行在每一列中都有最宽的标签,它仍然可以在屏幕上显示。

【问题讨论】:

介意分享你试过哪些方法?不推荐使用 shouldAutorotate。 @ChrisH:我可以把它放在那里,但如果我尝试在那里 [self.tableView reloadTable];,我会陷入无限循环。 检查在 UIViewcontroller 中配置视图旋转设置部分以及您尝试过哪些developer.apple.com/library/ios/documentation/uikit/reference/… @KunalBalani 他说他需要调整大小的标签位于自定义单元格中。 似乎使用正确的 autoresizingmask 或 autolayout 可以为您解决这个问题。据我所知,Apple 正试图让我们远离将旋转检测作为布局视图的一种手段。 【参考方案1】:

您不想依赖单元格内实际呈现的 UILabel 来计算“列”宽度。改为这样做:

    实现一个名为calculateColumnWidthsForInterfaceOrientation: 的方法,该方法采用UIInterfaceOrientation。在该方法中,使用UIInterfaceOrientationIsLandscape(orientation) 检查请求的方向是纵向还是横向。然后,根据方向浏览要在标签中显示的数据,并使用 NSString 的 sizeWithAttributes: 方法(或其派生方法之一)找到最宽的列宽。将这些值缓存在数组或其他东西中。 将setColumnWidths: 之类的方法添加到采用所需列宽的自定义表格视图单元格中。 在您的tableView:cellForRowAtIndexPath: 方法中,检索缓存的列宽并使用setColumnWidths: 方法将其设置在单元格上。 在您的单元格中,使用您刚刚设置的列宽来布局标签。 在您的视图控制器中,实现didRotateFromInterfaceOrientation:。在其中,使用给定的方向调用calculateColumnWidthsForInterfaceOrientation:,然后调用[self.tableView reloadData]。 最后,在viewDidLoad 中,调用[self calculateColumnWidthsForInterfaceOrientation:self.interfaceOrientation] 在第一次轮换之前对数据进行初始设置。

这应该可以解决问题。

更新: 单元格的总宽度应等于表格视图的总宽度。这可以通过自动布局或其他方式进行管理。该大小将反映在单元格的框架大小中。

更新 2: 由于我们正在讨论 popover,您可以简单地关闭 willRotateToInterfaceOrientation:duration: 中的弹出框,然后在 didRotateFromInterfaceOrientation: 中完成旋转后以新的所需尺寸再次显示它。

【讨论】:

大部分是我已经在做的。 sizeWithFont: 已被贬值,这就是为什么我需要渲染 UILabels 来计算我的列宽。如何根据方向计算单元格的总宽度(请参阅我对 RahulVyas 对我的 OP 的评论的回复)。另外,didRotateFromInterfaceOrientation 是另一种已被贬值的轮换方法,所以我回到我最初的问题“如何检测轮换”。我会将didRotateFromInterfaceOrientation 添加到我的 OP 中不起作用的列表中。 您对sizeWithFont: 方法的看法是正确的:我已将其更改为sizeWithAttributes:。但是,我不认为 didRotateFromInterfaceOrientation: 已被弃用。我在文档或标题中找不到任何内容。我已经对我的答案添加了另一个更新。 我试过didRotateFromInterfaceOrientation: 并在上面加了一个塞子——它没有被调用(至少在模拟器上——所以也许这是一个仅限模拟器的错误?)。 关于您的更新:我目前正在使用self.tableView.contentSize.width,但这只会返回当前方向的宽度。如果方向发生变化,我将如何提前获得宽度? 旋转时会发生什么?旋转设备时弹出框不会消失并重新出现吗?见***.com/questions/3859842/… 和developer.apple.com/library/ios/qa/qa1694/_index.html【参考方案2】:

在 layoutSubviews 中尝试重新计算子视图一个单元格

例如在 CustomCell.m 中

- (void)layoutSubviews


UIViewController *viewController = (id)[(AppDelegate *)[UIApplication sharedApplication].delegate window].rootViewController;

if (UIInterfaceOrientationIsPortrait(viewController.interfaceOrientation))
    self.backgroundColor = [UIColor redColor];
else
    self.backgroundColor = [UIColor greenColor];

【讨论】:

嗯,我不认为这与我正在寻找的东西很接近。不过感谢您的尝试。【参考方案3】:

您是否考虑过使用自动布局来定义您的 tableView 和单元格?结合updateConstraints 使用适当的约束来更新设备旋转时的单元格布局应该会有所帮助。使用这种方法,您可以设置每个“列”标签的preferredMaxLayoutWidth,并定义约束以处理适当的水平填充,无论方向如何。

另外,如果使用 iOS 7,那么您应该实现 popoverController:willRepositionPopoverToRect:inView: 来处理旋转时子视图的布局,除非您从条形按钮项目中呈现弹出框。我建议查看UIPopoverController Class Reference

【讨论】:

以上是关于在 iOS 7 中重新计算旋转时的子视图大小的主要内容,如果未能解决你的问题,请参考以下文章

如何在设备旋转后重新计算约束

UIcollectionView在ios 7中重新加载重叠

旋转后重新初始化 UIView 视图和子视图

不会重新计算基于数组值的计算属性

根据文本大小在视图中重新定位图像 - iOS

旋转视图和子视图