В моем приложении (код очень похож на демонстрацию Apple PhotoScroller от WWDC10) у меня есть 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 возвращает размеры, указывающие на то, что устройство находится в ландшафтном режиме, и мои вычисления раскладки работают правильно.
В iOS 5.x layoutSubviews получает только один раз, когда bounds.size возвращает измерения, указывающие портрет, и он не получает второй вызов, поэтому весь мой код вычисления испорчен.
Если пользователь физически поворачивает устройство, то layoutSubviews вызывается и работает правильно - поэтому пользователь, запускающий приложение в ландшафтном режиме (неправильно рисует), поворачивается к портрету (рисует исправно), а затем поворачивается назад к пейзажу (теперь рисуется правильно).
Этот второй "автоматический" вызов layoutSubviews, который мне не хватает.
Кто-нибудь еще замечает это или имеет какой-либо совет?
Update:
Я нашел это в примечаниях к выпуску UIKit для iOS 5, но я не уверен, насколько он релевантен или даже влияет на это изменение.
Обратные вызовы вращения в 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>>
Из них я вижу, что contentOffset UIScrollView в iOS 5 выглядит некорректно и что ландшафтный кадр имеет неправильные размеры в iOS 5, где они, похоже, имеют правильные размеры в iOS 4.