纵向xib调整为横向时需要改变UIScrollView contentSize

Posted

技术标签:

【中文标题】纵向xib调整为横向时需要改变UIScrollView contentSize【英文标题】:Need to change UIScrollView contentSize when portrait xib is adjusted to landscape 【发布时间】:2012-10-17 22:42:18 【问题描述】:

我有一个 UIViewController 和一个纵向的 iPad xib。当我的 iPad 处于横向并将该视图控制器放入 UISplitViewController 的详细信息窗格时,它会自动调整大小以适应这很棒。

但是,当我在 -viewDidLoad 中配置视图时,视图的最终大小还不是横向/大小。

-didRotateFromInterfaceOrientation: 方法和与之关联的其他方法在 UIViewController 已经在横向加载时不会被调用,那么我何时何地可以正确设置滚动视图的 contentSize 及其内容?

我只希望我的滚动视图垂直滚动,所以我想确保滚动视图中的内容视图在任何方向上都重新适合视图控制器的宽度。

无论我检查什么 .frame 或 .bounds,无论是在我的视图、我的滚动视图,甚至是我的 SplitViewController 的详细视图控制器,都会显示我的实际尺寸是多少。在横向使用 UISplitViewController 时,左侧为 320px 宽,这意味着右侧不应超过 704px 宽,但每当我检查视图和滚动视图的框架和边界时,它们报告为 768px 宽这是不正确的。

我的滚动视图显然只有 704px 宽,因为我可以正确地看到滚动指示器。

我错过了什么?

这是我在 -viewDidLoad 中的代码...

CGSize textSize = [self.purchase.textDescription sizeWithFont:self.labelTextDescription.font constrainedToSize:allowedSize lineBreakMode:UILineBreakModeWordWrap];

CGRect textFrame = self.labelTextDescription.frame;
textFrame.size.height = textSize.height;
self.labelTextDescription.frame = textFrame;

CGRect contentFrame = self.contentView.frame;
contentFrame.size.height += textSize.height;

if (contentFrame.size.width > self.scrollView.frame.size.width) 
    contentFrame.size.width = self.scrollView.frame.size.width;


self.contentView.frame = contentFrame;

[self.scrollView addSubview:self.contentView];
self.scrollView.contentSize = self.contentView.frame.size;

【问题讨论】:

你能贴出你设置内容大小的代码吗?是否在 viewDidLoad 中? 是的,在 viewDidLoad 中,我已经添加了代码。 你的 UIScrollView 的内容大小在旋转时真的会发生变化吗?内容不一样,大小不一样吗? 不,它没有改变,我也没有旋转。我的 iPad 在加载视图控制器之前处于横向状态,在加载视图控制器后处于横向状态。但是,xib 是纵向的,这意味着它会自动调整大小。我想主动保持内容的大小与滚动视图一样宽,以便它只能垂直滚动而不是水平滚动。 scrollView 的框架和边界在 -viewDidLoad、-viewWillAppear 和 -viewDidAppear 期间显示为 768w x 960h,即使它在横向模式下位于 UISplitViewController 的详细信息窗格中,这意味着它不应该比768h高,比768w要薄。我可以完美地看到 UIScrollView 的滚动条,所以我知道它已经调整到可用的宽度和高度,但是框架和边界没有反映它。 【参考方案1】:

布局视图和设置滚动视图的contentSize 的适当时间是在运行循环的布局阶段。在这个阶段,UIKit 将layoutSubviews 消息发送到任何被标记为需要布局并且在窗口中的视图。当各种事情发生时,视图会自动标记为需要布局,包括第一次添加到窗口层次结构时,给它一个新的子视图时,以及它的大小发生变化时。您还可以通过发送setNeedsLayout 消息手动将视图标记为需要布局。

当视图收到layoutSubviews 消息时,UIKit 已经将layoutSubviews 发送给任何需要它的视图的祖先(它的父视图及更高版本),并且它已经根据其自动调整大小调整了其框架mask 或 autolayout 约束,并且它自己的子视图的框架已经根据它们的 autoresizing mask 或 autolayout 约束进行了调整。

如果self.view 已经是UIView 的自定义子类,最好的方法是简单地覆盖该类中的layoutSubviews。把你的布局代码放在那里,然后在那里设置滚动视图的contentSize

如果您没有使用自定义子类,并且您不想创建一个,那么您可以在视图控制器的 viewWillLayoutSubviewsviewDidLayoutSubviews 方法中进行布局,如果您的部署目标是 ios 5.0 或更高版本。您可能会猜到这些消息是何时发送的。 :)

在自动旋转期间,所有这些消息(layoutSubviewsviewWillLayoutSubviewsviewDidLayoutSubviews)都在自动旋转的动画块内发送,因此如果您使用其中一种方法进行布局,您还可以获得以下好处对布局的更改将在自动旋转动画期间进行动画处理。

【讨论】:

-viewDidLayoutSubviews 听起来很完美,但我需要支持回iOS4.3。对iOS4有什么建议吗?我没有使用任何自定义视图。 我会创建一个UIView 的子类并实现layoutSubviews 必须有一种方法可以确定我的视图控制器的实际大小...... 视图控制器没有尺寸。视图有大小。您可以依赖正确设置视图大小的最早时间是在布局过程中,在视图的父视图完成其子视图的布局之后。制作UIView 的子视图没什么大不了的。如果你想偷懒,只需给视图一个unsafe_unretained 引用返回给视图控制器,并让它的layoutSubviews 方法向视图控制器发送一条消息以完成实际的布局工作。 是的,我知道是视图,我打错了。我的观点仍然存在,在视图控制器生命周期中必须有一种方法可以知道 self.view 的实际大小是多少。【参考方案2】:

首先,如果您不想在旋转时调整视图大小,请检查自动调整大小掩码。如果您在界面构建器中构建了视图,请检查它是否在超级视图发生变化时没有改变它的大小:

您可以使用self.interfaceOrientation 检查UIViewController 的当前界面方向。如果您想手动设置视图,这可能会对您有所帮助。

此外,如果您需要手动调整尺寸,请在执行旋转之前(或之后)将所需的帧设置为您的视图:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;

【讨论】:

【参考方案3】:

我建议查询状态栏方向以获取viewDidLoad 中的当前旋转我建议不要依赖自动调整滚动视图的大小,因为它往往会变得棘手。检查状态栏并根据此按比例调整大小。

[UIApplication sharedApplication].statusBarOrientation

【讨论】:

以上是关于纵向xib调整为横向时需要改变UIScrollView contentSize的主要内容,如果未能解决你的问题,请参考以下文章

带 2 XIB 的旋转纵向横向

以纵向和横向初始化 UIViewController

为纵向和横向模式调整 UIImage 的大小

一个视图控制器,纵向和横向两个视图

使用自动布局调整 xib 元素的宽度

当方向从横向更改为纵向时,UInavigationbar 背景图像无法正确调整大小