在 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 中重新计算旋转时的子视图大小的主要内容,如果未能解决你的问题,请参考以下文章