iOS5,UIScrollView和layoutSubviews行为

时间:2011-10-18 15:15:39

标签: objective-c ios uiscrollview ios5

在我的应用程序中(代码与WWDC10的Apple的PhotoScroller演示非常相似),我有一个UIScrollView。在滚动视图中,我已使用以下代码覆盖layoutSubviews:

- (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返回指示设备处于landsacpe并且我的布局计算正常工作的尺寸。

在iOS 5.x中,layoutSubviews仅调用一次,其中bounds.size返回指示纵向的尺寸,并且它没有得到第二次调用,因此我的所有计算代码都搞砸了。

如果用户在物理上旋转设备,则layoutSubviews被调用并正常工作 - 因此用户在横向上启动应用程序(绘制不正确),旋转为纵向(绘制正确),然后旋转回横向(现在正确绘制)

它是我缺少的第二次“自动”调用layoutSubviews。

是否有人注意到这一点或有任何建议?

更新

我确实在iOS 5的UIKit发行说明中找到了这个,但我不确定它是否相关,甚至是这种变化的影响。

  

iOS 5中的旋转回调不适用于通过全屏显示的视图控制器。这意味着如果您的代码在另一个视图控制器上呈现视图控制器,然后用户随后将设备旋转到不同的方向,则在解雇时,底层控制器(即呈现控制器)将不会接收任何旋转回调。但请注意,呈现控制器在重新显示时将接收aviewWillLayoutSubviews调用,并且可以从此方法查询interfaceOrientation属性并用于正确布局控制器。

进一步更新:

使用[UIView recursiveDescription]来转储视图层次结构,我得到以下输出:

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中看起来具有正确的尺寸。

3 个答案:

答案 0 :(得分:2)

最终,我偶然发现了解决这个问题的方法。我会在这里提供答案,因为它可能对其他人有帮助。

我的解决方案是在我的视图控制器上实现- (void)viewWillAppear:(BOOL)animated方法。我没有一个,我在- (void) viewDidLoad方法中拥有了所有的设置逻辑。

特别是,我实施了以下内容:

- (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就可以了。

当我进行测试时,所有在iOS4中都能正常工作。

也许,我应该一直在阅读bounds中的viewWillAppear属性,这可能是更正确的行为。但是,在iOS4和iOS 5之间发生了一些变化,我无法找到文档。

`

答案 1 :(得分:1)

我遇到了类似的问题。不知何故,我解决了它。 在iOS 5.x中,当您创建新的XIB文件时,默认情况下,它的Orientation设置为Portrait。因此,您的layoutSubviews只能通过bounds.size调用一次,返回指示纵向的尺寸,并且不会进行第二次调用。

只是,做一件事,在XIB设计中将XIB方向设置为Landscape 。因此,您的代码将首次检查方向,它将作为Landscape&amp; amp;您的所有布局都将相应设置。

答案 2 :(得分:0)

我遇到了类似的问题。我通过硬编码边界rect来解决它,具体取决于视图控制器的界面方向,并可能在viewDidLoad和viewWillAnimateToInterfaceOrientation上标记setNeedsLayout的scrollview。