ios swift ios8 screen-rotation size-classes

Los cambios de animación durante la rotación del dispositivo en función del elemento de tamaño se realizarán una vez que se complete la rotación.



swift ios8 (2)

Tengo una configuración dinámica de botones que se ajustan automáticamente en ancho y alto en función de las restricciones de diseño automático configuradas en un guión gráfico. Cuando está en retrato, los botones tienen anchuras y alturas iguales, por lo que el marco es perfectamente cuadrado, y cuando el dispositivo se gira hacia el paisaje, los botones se hacen cada vez más cortos. He puesto cornerRadius en las capas de los botones, por lo que son perfectamente circulares cuando están en el retrato y eso funciona bien, pero cuando giro para hacer un paisaje, el radio de la esquina ya no se ve correctamente. Necesito cambiar eso para que se convierta en un óvalo. El problema es que no importa dónde intente poner ese código, no puedo obtener el ancho y la altura correctos que tendrán los botones después de que ocurra la rotación. Quiero que esto ocurra mientras el dispositivo está girando; no quiero esperar hasta que la rotación se haya completado. Idealmente, la cornerRadius animaría el cambio mientras la transición se anima.

Si utilizo viewWillLayoutSubviews o viewDidLayoutSubviews , obtiene correctamente el marco del botón cuando se inicia la aplicación, pero al rotar al paisaje se llama a este método antes de que se actualice el marco del botón para la nueva orientación, por lo que no puedo calcular el radio correcto de la esquina.

Si utilizo viewWillTransitionToSize:withTransitionCoordinator: o willTransitionToTraitCollection:withTransitionCoordinator: o willRotateToInterfaceOrientation , no se llama cuando se inicia la aplicación, y al girar el dispositivo se llama antes de que el marco se actualice para el nuevo tamaño.

Si uso willAnimateRotationToInterfaceOrientation , no se llama cuando se inicia la aplicación, pero al girar el dispositivo obtiene correctamente el nuevo marco de botón. Pero este método está en desuso.

Entonces, la pregunta es, ¿qué método puede usar para establecer las propiedades de un botón según el tamaño que tendrá el botón cuando se complete la rotación, que se llama antes de que se complete la rotación?

Tenga en cuenta que debe invocarse para cada cambio de orientación, no solo para cambiar la clase de tamaño (rotar el iPad no cambia la clase de tamaño). Solo necesito compatibilidad con iOS 8.0+.

Este es el código que estoy colocando en los métodos para saber si está obteniendo el tamaño correcto:

println("/(button.frame.size.width) x /(button.frame.size.height)")


La respuesta es usar viewWillTransitionToSize:withTransitionCoordinator: con su código colocado dentro del cierre de la animación del UIViewControllerTransitionCoordinator animateAlongsideTransition: . Esto le permitirá animar los cambios en función del tamaño que tendrá cuando se complete la rotación.

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) coordinator.animateAlongsideTransition({ (context: UIViewControllerTransitionCoordinatorContext!) -> Void in self.updateButtonsCornerRadius() }, completion: nil) }

Este método no se self.updateButtonsCornerRadius() cuando se inicia la aplicación, por lo que también querrás llamar a self.updateButtonsCornerRadius() en viewDidLoad .


A continuación CADisplayLink cómo se podría usar CADisplayLink para actualizar las propiedades durante cada fotograma de la animación, pero hay una manera más fácil. Subclase el botón (o vista o lo que sea) con un layoutSubviews que actualiza el radio de la esquina:

class RoundedCornerView: UIView { override func layoutSubviews() { super.layoutSubviews() layer.cornerRadius = min(bounds.width, bounds.height) / 2 } }

Luego, durante la animación, a medida que cambia el tamaño del marco, el radio de la esquina se actualiza automáticamente:

Como señala Joey, uno puede usar viewWillTransitionToSize para recibir notificaciones sobre el nuevo tamaño, y luego usar animateAlongsideTransition para coordinar su animación adicional junto con la animación principal.

Si desea animar una propiedad no animable, como el radio de la esquina (en las animaciones basadas en bloques, de todos modos), puede usar un enlace de visualización para la duración de la animación. Esto llama efectivamente a nuestro método para cada fotograma de la animación de rotación. por lo tanto, tendremos un método que mira la capa de presentación (que muestra el estado actual de una capa de animación media) para ajustar el radio de la esquina sobre la marcha. También puede usar animateAlongsideTransition para esto, pero en este caso no estamos usando el cierre de la animation , sino que simplemente usamos el cierre de completion para saber cuándo se realiza la animación y, por lo tanto, puede detener el enlace de visualización:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) let displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:") displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes) coordinator.animateAlongsideTransition(nil) { (context) -> Void in displayLink.invalidate() } } func handleDisplayLink(displayLink: CADisplayLink) { updateButtonsCornerRadius() } func updateButtonsCornerRadius() { for button in [button1, button2] { let presentationLayer = button.layer.presentationLayer() as CALayer let minDimension = min(presentationLayer.frame.size.width, presentationLayer.frame.size.height) button.layer.cornerRadius = minDimension / 2.0 } }

Francamente, no estoy seguro de que esta animación en el radio de la esquina sea suficiente para justificar este enlace de visualización (tuve que reducir la velocidad de las animaciones en el simulador con el comando + T para apreciar la diferencia), pero esto ilustra la idea básica.