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