objective-c - scrollview swift
comportamiento iOS5, UIScrollView y layoutSubviews (3)
Estoy teniendo un problema similar. Lo solucioné codificando los límites rect según la orientación de la interfaz del controlador de vista y posiblemente marcando scrollview para setNeedsLayout en viewDidLoad y viewWillAnimateToInterfaceOrientation.
En mi aplicación (código muy similar a la demo de PhotoScroller de Apple de WWDC10), tengo un UIScrollView. Dentro de la vista de desplazamiento, he redefinido layoutSubviews con un código como:
- (void) layoutSubviews {
[super layoutSubviews];
// center the image as it becomes smaller than the size of the screen
CGSize boundsSize = self.bounds.size;
...
}
En iOS 4.x si la aplicación se inicia en modo horizontal (el usuario la mantiene horizontal), layoutSubviews recibe dos llamadas (muy rápidamente). La primera vez que se invoca, boundsSize tiene dimensiones que lo indican en vertical, pero inmediatamente después se vuelve a llamar y self.bounds.size devuelve dimensiones que indican que el dispositivo está en landsacpe y mis cálculos de diseño funcionan correctamente.
En iOS 5.x, layoutSubviews solo se llama una vez con bounds.size devolviendo las dimensiones que indican el retrato y no recibe la segunda llamada, por lo que todo mi código de cálculo está en mal estado.
Si el usuario rota físicamente el dispositivo, se llama a layoutSubviews y funciona correctamente, por lo que el usuario inicia la aplicación en horizontal (dibuja incorrectamente), gira a vertical (dibuja de manera correcta) y luego vuelve al paisaje (ahora se dibuja correctamente).
Es esa segunda llamada "automática" de diseño. Visitas que me estoy perdiendo.
¿Alguien más nota esto o tiene algún consejo?
Actualizar:
Lo encontré en las notas de la versión de UIKit para iOS 5, pero no estoy seguro si es relevante o incluso cuál es el impacto de este cambio.
Las devoluciones de llamadas de rotación en iOS 5 no se aplican para ver los controladores que se presentan en una pantalla completa. Lo que esto significa es que si su código presenta un controlador de vista sobre otro controlador de vista, y luego el usuario gira el dispositivo a una orientación diferente, al momento del rechazo, el controlador subyacente (es decir, el controlador que presenta) no recibirá ninguna devolución de llamada de rotación. Sin embargo, tenga en cuenta que el controlador que se presenta recibirá una llamada a ViewLayoutSubviews cuando se vuelva a mostrar, y la propiedad interfaceOrientation se puede consultar desde este método y se puede usar para diseñar el controlador correctamente.
Otras actualizaciones:
Usando [UIView recursiveDescription]
, para volcar las jerarquías de vista, obtuve el siguiente resultado:
iOS 4 (que funciona correctamente):
Retrato:
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>>
Paisaje:
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 (que funciona incorrectamente):
Retrato:
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>>
Paisaje:
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>>
A partir de estos, puedo ver que contentOffset de UIScrollView en iOS 5 parece incorrecto y que el marco horizontal tiene dimensiones incorrectas en iOS 5, donde parecen tener las dimensiones correctas en iOS 4.
Estaba teniendo un problema similar. De alguna manera, lo resolví. En iOS 5.x, cuando crea un nuevo archivo XIB, de forma predeterminada, su orientación se establece en Vertical. Entonces, su layoutSubviews solo se llama una vez con bounds.size devolviendo las dimensiones que indican portrait y no recibe la segunda llamada.
Solo, haga una cosa, configure su orientación de XIB en Paisaje en diseño XIB . Por lo tanto, su código verificará la orientación por primera vez, lo obtendrá como Paisaje y todos sus diseños se establecerán en consecuencia.
Finalmente, me encontré con la solución a este problema para mí. Proporcionaré la respuesta aquí, ya que puede ser útil para otros.
La solución para mí fue implementar el - (void)viewWillAppear:(BOOL)animated
método - (void)viewWillAppear:(BOOL)animated
en mi controlador de vista. No tenía uno y tenía toda mi lógica de configuración en el método - (void) viewDidLoad
.
En particular, implementé lo siguiente:
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
CGRect bounds = pagingScrollView.bounds; // <=== this was the key
// ... use the bounds in my view setup logic
}
Me parece que ha habido un cambio en iOS 5 (de versiones anteriores del SO). Cuando se carga una vista cuando un dispositivo está en el paisaje, la propiedad de bounds
en una vista no refleja la transformación de orientación hasta que viewWillAppear
. Anteriormente, el valor de los límites era correcto para mí en viewDidLoad
pero al mover los cálculos y la lectura de la propiedad de los bounds
de allí a viewWillAppear
el problema.
Todo funciona bien en iOS4 también, cuando hice mi prueba.
Tal vez, siempre debería haber estado leyendo la propiedad de bounds
en viewWillAppear
y bien podría ser el comportamiento más correcto . Sin embargo, algo ha cambiado entre iOS4 e iOS 5 en el que no he podido encontrar documentación.
`