homework - iOS Landscape Orientation handling behind the scenes
best iphone apps 2018 (2)
Gran respuesta del príncipe. Me gustaría agregar una cita de los documentos sobre la propiedad de frame
de UIView
:
Advertencia : si la propiedad de
transform
no es la transformación de identidad, el valor de esta propiedad no está definido y, por lo tanto, debe ignorarse.
La propiedad de bounds
, por otro lado, se expresa en el propio sistema de coordenadas de la vista, por lo que nunca cambia, sin importar qué transform
establezca.
Actualización: con respecto a su último párrafo, ¿qué le hace pensar que este comportamiento es extraño o ha cambiado? La única forma en que iOS puede rotar su jerarquía de vistas es cambiando las transformaciones de vista. Entonces, si desea que todas sus vistas en diferentes controladores de vista se orienten de la misma manera, debe usar algún tipo de controlador de vista de navegación, o presentar sus controladores de manera modal. De esta forma, cada controlador rotará su vista de acuerdo con las mismas reglas y no tendrá que administrar manualmente las transformaciones entre vistas.
En los primeros días se podía ver el código como este:
UIViewController *ctrl = ...;
[window addSubview.ctrl.view];
Esto era antes de que window
tuviera la propiedad rootViewController
, y las personas tendían a abusar de esto para sus propias vistas, lo que causaría resultados sorprendentes cuando el dispositivo girara. Si dices que ya no ves este código, eso definitivamente es un cambio, y un cambio para mejor porque ese código estaba roto. Entonces la gente simplemente aprendió a escribir código que funciona correctamente en presencia de cambios de orientación.
Si tiene un juego con toda su interfaz de usuario prestada por el motor del juego, solo necesita un controlador de vista (raíz). En este caso, no necesita preocuparse por las transformaciones. Solo consulta los límites de glView
y ajusta tu glViewport
y los elementos del juego en consecuencia. Dado que glView
tendrá diferentes límites de dispositivos diferentes, su juego se escalará con gracia en todos ellos, siempre que no haga suposiciones sobre el tamaño real de la pantalla y la orientación actual de su vista.
¿Alguien puede darme una explicación detallada de por qué iOS maneja su orientación horizontal de la forma en que lo hace con respecto al marco y la transformación?
De lo que estoy hablando es de este comportamiento siguiente que se muestra al registrar la descripción de las vistas en los diversos métodos de View Lifecycle:
viewDidLoad: "UIView: 0x1edb5ba0; frame = (0 0; 568 320); autoresize = W+H; layer = <CALayer: 0x1edb5c50>"
viewWillAppear: "UIView: 0x1edb5ba0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x1edb5c50>"
viewDidAppear: "UIView: 0x1edb5ba0; frame = (0 0; 320 568); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x1edb5c50>"
Las repercusiones de esto son sutiles, pero muy intrigantes.
Por ejemplo, inicio mi aplicación con Orientación de interfaz inicial y Orientaciones de interfaz admitidas ambas configuradas en "Horizontal (botón de inicio a la derecha)"
Luego muestro mi rootViewController así:
self.viewController = [[MyViewController alloc] initWithNibName:nil bundle:nil];
self.window.rootViewController = self.viewController;
Este .xib tiene su orientación establecida en Horizontal y su marco está configurado en 0, 0, 568, 320. Se visualiza correctamente y puedo tocar todos los puntos de la pantalla.
El problema luego viene cuando presento una subvista así:
SomeView *someView = [[SomeView alloc] initWithFrame:self.view.frame];
[self.view addSubview:someView];
En este momento, self.view.frame se informa como (0 0; 320 568) y self.view.transform se informa como transform = [0, 1, -1, 0, 0, 0]. En el mejor de los casos, el resultado final es que solo puedo tocar el lado izquierdo de 320 píxeles de la vista que acabo de mostrar, el peor caso es que el diseño de la vista se destruye.
Gracias a varias preguntas de SO, aprendí que la forma correcta de hacerlo es la siguiente:
SomeView *someView = [[SomeView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:someView]
Lo que no he aprendido es por qué, y tengo mucha curiosidad sobre eso.
Lo que más me llena de curiosidad es por qué la vista se manipula de la manera en que está durante la creación de instancias y la visualización.
Ha pasado bastante tiempo desde que me he enredado con una aplicación de solo paisaje, pero por alguna razón creo que la implementación actual de esto difiere de las versiones anteriores de iOS, ¿es correcto?
Según apple, de forma predeterminada, una aplicación admite orientaciones vertical y horizontal. Cuando la orientación de un dispositivo basado en iOS cambia, el sistema envía una notificación UIDeviceOrientationDidChangeNotification para informar a las partes interesadas que se produjo el cambio. De forma predeterminada, el marco UIKit escucha esta notificación y la usa para actualizar automáticamente la orientación de su interfaz. Esto significa que, con solo unas pocas excepciones, no debería necesitar manejar esta notificación en absoluto.
La razón por la que tiene que dar límites en lugar de marco es simple. Una vez que la aplicación está en el paisaje, su ancho y alto se intercambian en comparación con la vista de retrato. Entonces esto lleva al comportamiento corrupto. Pero al dar los límites, toma en consideración la orientación de la vista y toma la altura y el ancho en consecuencia.
Cuando tiene controladores de vista muy cerca de la parte superior de la jerarquía de vistas (o de hecho en la parte superior), puede encontrar que obtiene este efecto de "intercambio" del ancho y alto. El intercambio generalmente se manifiesta en el marco, pero no en los límites de la vista. Esto se debe a que los límites son efectivamente algunas transformaciones aplicadas al marco, y algunas veces estas transformaciones incluyen una rotación de 90 grados (debido a que el dispositivo está en modo horizontal). Tenga en cuenta que el momento exacto en que verifica la propiedad del marco también puede ser importante. Si está revisando la propiedad después de la vista cargada pero antes de que haya aparecido en la pantalla, puede obtener el resultado "incorrecto".