問題描述
在我的應用程序(代碼與 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 行為的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!