在我的应用程序(代码与 WWDC10 中 Apple 的 PhotoScroller 演示非常相似)中,我有一个 UIScrollView.在滚动视图中,我使用如下代码覆盖了 layoutSubviews:
In my app (code very similar to Apple's PhotoScroller demo from WWDC10), I have a UIScrollView. Within the scroll view I have overwridden layoutSubviews with code like:
- (void) layoutSubviews {
[super layoutSubviews];
// center the image as it becomes smaller than the size of the screen
CGSize boundsSize = self.bounds.size;
...
}
在 iOS 4.x 中,如果应用程序以横向模式启动(用户拿着它横向),那么 layoutSubviews 会被调用两次(非常快).第一次调用时,boundsSize 具有指示其纵向的尺寸,但随后立即再次调用它,并且 self.bounds.size 返回指示设备处于横向的尺寸,并且我的布局计算工作正常.
In iOS 4.x if the application starts up on landscape mode (user is holding it landscape), then layoutSubviews gets called twice (very quickly). The first time its called, boundsSize has dimensions that indicate its in portrait but immediately afterwards it gets called again and self.bounds.size returns dimensions that indicate the device is in landsacpe and my layout calculations work correctly.
在 iOS 5.x 中,layoutSubviews 只被调用一次,bounds.size 返回表示纵向的尺寸并且它没有得到第二次调用,所以我所有的计算代码都搞砸了.
In iOS 5.x, layoutSubviews only gets called once with bounds.size returning dimensions indicating portrait and it doesn't get the second call, so all my calculation code is messed up.
如果用户物理旋转设备,则 layoutSubviews 会被调用并正常工作 - 因此用户以横向启动应用程序(绘制不正确),旋转为纵向(绘制正确),然后旋转回横向(现在可以正确绘制).
If the user physcially rotates the device then layoutSubviews gets called and works correctly -- so a user starting the app in landscape (draws incorrectly), rotates to portrait (draws correcty) and then rotates back to landscape (now draws correctly).
这是我缺少的第二次自动"调用 layoutSubviews.
Its that second "automatic" call of layoutSubviews that I'm missing.
还有其他人注意到这一点或有什么建议吗?
Anybody else notice this or have any advice?
更新:
我确实在 iOS 5 的 UIKit 发行说明中找到了这一点,但我不确定它是否相关,甚至不确定此更改的影响.
I did find this in the UIKit release notes for iOS 5, but I'm not sure if it's relevent or even what the impact is of this change.
iOS 5 中的旋转回调不适用于全屏显示的视图控制器.这意味着如果您的代码在另一个视图控制器上显示一个视图控制器,然后用户随后将设备旋转到不同的方向,则在关闭时,底层控制器(即呈现控制器)将不会收到任何旋转回调.但请注意,呈现控制器在重新显示时会收到 viewWillLayoutSubviews 调用,并且可以从该方法中查询 interfaceOrientation 属性并用于正确布局控制器.
Rotation callbacks in iOS 5 are not applied to view controllers that are presented over a full screen. What this means is that if your code presents a view controller over another view controller, and then the user subsequently rotates the device to a different orientation, upon dismissal, the underlying controller (i.e. presenting controller) will not receive any rotation callbacks. Note however that the presenting controller will receive aviewWillLayoutSubviews call when it is redisplayed, and the interfaceOrientation property can be queried from this method and used to lay out the controller correctly.
进一步更新:
使用 [UIView recursiveDescription]
,转储视图层次结构,我得到以下输出:
Using [UIView recursiveDescription]
, to dump the view hierarchies, I got the following output:
iOS 4(工作正常):
肖像:
2011-12-19 15:57:06.400 stroom[10889:11603] <0x5e7f9b0 stroomViewController.m:(402)> <UIView: 0x6a6f2f0; frame = (0 0; 768 1024); autoresize = W+H; layer = <CALayer: 0x6a659d0>>
| <UIScrollView: 0x5e911e0; frame = (-20 0; 808 1024); clipsToBounds = YES; autoresize = LM+W+RM+TM+H+BM; layer = <CALayer: 0x5e91370>; contentOffset: {0, 0}>
| | <stroomFullScreenPhotoScrollView: 0x5ea1010; baseClass = UIScrollView; frame = (20 0; 768 1024); clipsToBounds = YES; layer = <CALayer: 0x5ea0940>; contentOffset: {0, 0}>
| | | <UIImageView: 0x5ea2600; frame = (0 224; 768 576); transform = [0.75, 0, 0, 0.75, 0, 0]; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x5ea0890>>
风景:
2011-12-19 15:57:34.522 stroom[10889:11603] <0x5e7f9b0 stroomViewController.m:(402)> <UIView: 0x6d96c30; frame = (0 0; 768 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x6d66440>>
| <UIScrollView: 0x5e9eb70; frame = (-27 0; 1078 768); clipsToBounds = YES; autoresize = LM+W+RM+TM+H+BM; layer = <CALayer: 0x5eadde0>; contentOffset: {0, 0}>
| | <stroomFullScreenPhotoScrollView: 0x6dab850; baseClass = UIScrollView; frame = (20 0; 1038 768); clipsToBounds = YES; layer = <CALayer: 0x6dab2e0>; contentOffset: {0, 0}>
| | | <UIImageView: 0x5e97f70; frame = (0 224; 1024 768); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x5e97fa0>>
iOS 5(工作不正常):
肖像:
2011-12-19 15:55:59.530 stroom[10850:16103] <0x848b520 stroomViewController.m:(402)> <UIView: 0xa884710; frame = (0 0; 768 1024); autoresize = W+H; layer = <CALayer: 0xa8849a0>>
| <UIScrollView: 0xa883820; frame = (-20 0; 808 1024); clipsToBounds = YES; autoresize = LM+W+RM+TM+H+BM; layer = <CALayer: 0xa883a80>; contentOffset: {0, 0}>
| | <stroomFullScreenPhotoScrollView: 0x8699630; baseClass = UIScrollView; frame = (20 0; 768 1024); clipsToBounds = YES; layer = <CALayer: 0x8699360>; contentOffset: {0, 0}>
| | | <UIImageView: 0x869a7c0; frame = (0 0; 768 576); transform = [0.75, 0, 0, 0.75, 0, 0]; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x869a800>>
风景:
2011-12-19 15:56:32.521 stroom[10850:16103] <0x848b520 stroomViewController.m:(402)> <UIView: 0x8498530; frame = (0 0; 768 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x8498560>>
| <UIScrollView: 0x849ead0; frame = (-27 0; 1077 768); clipsToBounds = YES; autoresize = LM+W+RM+TM+H+BM; layer = <CALayer: 0x848f390>; contentOffset: {808, 0}>
| | <stroomFullScreenPhotoScrollView: 0x81e4b80; baseClass = UIScrollView; frame = (828 0; 768 1024); clipsToBounds = YES; layer = <CALayer: 0x81e7dc0>; contentOffset: {0, 0}>
| | | <UIImageView: 0x81e5090; frame = (0 0; 768 576); transform = [0.75, 0, 0, 0.75, 0, 0]; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x81e5010>>
从这些我可以看到,iOS 5 中 UIScrollView 的 contentOffset 看起来不正确,并且横向框架在 iOS 5 中的尺寸不正确,而在 iOS 4 中它们似乎具有正确的尺寸.
From these I can see that the contentOffset of the UIScrollView in iOS 5 looks incorrect and that the landscape frame have incorrect dimensions in iOS 5 where they appear to have correct dimensions in iOS 4.
最终,我偶然发现了这个问题的解决方案.我会在这里提供答案,因为它可能对其他人有帮助.
Eventually, I stumbled upon the solution to this problem for me. I'll provide the answer here as it maybe helpful for others.
我的解决方案是在我的视图控制器上实现 - (void)viewWillAppear:(BOOL)animated
方法.我没有,我的所有设置逻辑都在 - (void) viewDidLoad
方法中.
The solution for me was to implement the - (void)viewWillAppear:(BOOL)animated
method on my view controller. I didn't have one and I had all my setup logic in - (void) viewDidLoad
method.
特别是,我实现了以下内容:
In particular, I implemented the following:
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
CGRect bounds = pagingScrollView.bounds; // <=== this was the key
// ... use the bounds in my view setup logic
}
在我看来,iOS 5 发生了变化(与以前版本的操作系统相比).当设备处于横向时加载视图时,视图上的 bounds
属性在 viewWillAppear
之前不会反映方向转换.以前, viewDidLoad
中的边界值对我来说是正确的,但是将 bounds
属性的计算和读取从那里移到 viewWillAppear
中把戏.
It appears to me, that there has been a change in iOS 5 (from previous versions of the OS). When a view is loaded when a device is in landscape, the bounds
property on a view does not reflect the orientation transformation until viewWillAppear
. Previously, the bounds value was correct for me in viewDidLoad
but moving the calculations and reading of the bounds
property out of there and into viewWillAppear
did the trick.
当我进行测试时,在 iOS4 中也一切正常.
All works fine in iOS4 as well, when I did my testing.
也许,我应该一直在阅读 viewWillAppear
中的 bounds
属性,这可能是更正确的行为.但是,iOS4 和 iOS 5 之间发生了一些我无法找到相关文档的变化.
Perhaps, I should always have been reading the bounds
property in viewWillAppear
and it may well be the more correct behavior. However, something has changed in between iOS4 and iOS 5 that I have not been able to find documentation on.
`
这篇关于iOS5、UIScrollView 和 layoutSubviews 行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!