Hola a todos!
Mi nombre es Ilya, soy de Tinkoff.ru. Le traduje un artículo de Geoff Hackworth sobre cómo cambió el estilo de presentación modal en iOS 13, qué afectó y cómo funciona la compatibilidad con versiones anteriores de iOS y Xcode.

Introduccion
Al momento de escribir, WWDC 2019 está llegando a su fin. Al igual que muchos desarrolladores para iOS, proceso lentamente toda la información nueva que Apple nos ha proporcionado, y en las próximas semanas (¡y meses!) Trataré de ver tantos videos como pueda.
Tenía tres preguntas sobre mis propias aplicaciones:
- ¿Mis aplicaciones actuales funcionan sin problemas en iOS 13? Apple tiene una larga historia de compatibilidad con versiones anteriores, basada en la versión de Xcode con la que se creó la aplicación. La historia muestra que las aplicaciones creadas en Xcode 10 para iOS 13 se comportarán como si se estuvieran ejecutando en iOS 12. Pero este no es siempre el caso.
- ¿Mis aplicaciones funcionan al compilar con Xcode 11 / iOS 13? La compilación utilizando las últimas herramientas permite que la aplicación funcione de una manera nueva, evitando la compatibilidad con versiones anteriores de iOS. ¿Hay algo roto?
- ¿Qué cambios pueden / deben hacerse para que mis aplicaciones funcionen mejor o aprovechen las nuevas características de iOS 13? Esta es la tarea más grande, y llevará más tiempo estudiarla e implementarla. Este estudio es para un artículo separado.
Todavía no he instalado iOS 13 en un dispositivo real, pero puedo probar el elemento # 1 instalando aplicaciones creadas en Xcode-10 en el simulador de iOS 13.
Todavía estoy trabajando en el punto # 2, pero en base a mis pruebas iniciales y la lectura de tweets de otros desarrolladores que hicieron descubrimientos similares, encontré una serie de cambios de comportamiento en mis aplicaciones al compilar con Xcode 11. Tengo muchos videos para mirar e información para asimilación, pero en esta publicación quiero centrarme en cambios inmediatamente perceptibles y potencialmente destructivos en la presentación del UIViewController en iOS 13.
Cambiar el estilo de presentación modal predeterminado
Por defecto, una presentación modal ahora es una "página" (Hoja de página original), en lugar de una pantalla completa. La documentación para modalPresentationStyle
dice:
El valor predeterminado es UIModalPresentationAutomatic para iOS, que comienza con iOS 13.0, y UIModalPresentationFullScreen en versiones anteriores.
De manera predeterminada, el UIViewController, si modalPresentationStyle
configurado como modalPresentationStyle, usa UIModalPresentationPageSheet, pero los controladores del sistema pueden usar otros estilos de visualización para UIModalPresentationAutomatic.
Los efectos de este cambio son diferentes para el iPhone y iPad.
Presentación modal en iPhone
Los estilos de presentación de Hoja de página, Hoja de formulario y Popover en iPhone se adaptan a pantalla completa a menos que se UIAdaptivePresentationControllerDelegate
método UIAdaptivePresentationControllerDelegate
para evitar la adaptación. Por ejemplo, la pantalla de configuración se puede presentar en el estilo de Hoja de formulario, para que se muestre en modo de pantalla completa en el iPhone y en forma reducida en el iPad. Técnicamente, la apariencia / adaptación depende del ancho. Las presentaciones de Hoja de página / Hoja de formulario / Popover en dispositivos Landscape iPhone Plus y XS Max no cubren toda la pantalla porque tienen el ancho habitual. La apariencia del iPad depende del tamaño de la diapositiva y del modo multitarea.
Las siguientes capturas de pantalla muestran la presentación de la Hoja de formulario en iPhone XS para tres casos: compilación en Xcode 10 para iOS 12, compilación en Xcode 10 para iOS 13, compilación en Xcode 11 para iOS 13.

La compatibilidad con versiones anteriores de iOS 12 con iOS 13 para generar Xcode 10 da como resultado una vista de pantalla completa. El estilo del UITableView agrupado ha cambiado en iOS 13 para ocultar el espacio sobre la primera sección en ausencia de un título. Incluso la compilación de Xcode 10 / iOS 12 se comporta de manera diferente cuando se inicia en iOS 13, que no es lo que esperaba.
El mayor cambio en iOS 13, por supuesto, es la pantalla de la tarjeta (original. Apariencia similar a la tarjeta). El UIViewController se ha reducido de tamaño, y su parte superior todavía es ligeramente visible detrás del nuevo UIViewController. La UIWindow detrás del UIViewController raíz también es un poco visible. El fondo negro de UIWindow se ve muy bien por defecto, especialmente en dispositivos con una muesca. Algunas de mis aplicaciones configuraron el fondo UIWindow en blanco (por razones que ya no recuerdo), y se veía bastante feo. ¡Lo arreglé rápidamente!
Comportamiento UIViewController en nuevo estilo de visualización modal
Si el UIViewController presentado muestra otro UIViewController, las tarjetas se superponen con una bonita animación. Tenga en cuenta que solo el último UIViewController que se muestra y un poco del anterior son visibles:

Otra diferencia de comportamiento potencialmente importante es lo que sucede con el UIViewController que muestra (presentación original). Una presentación de pantalla completa (presentación de pantalla completa) que cubre completamente el UIViewController eliminará el UIViewController de la jerarquía. Pero en el caso de la nueva presentación de la tarjeta, el UIViewController debe permanecer en la jerarquía porque todavía está visible. Sin embargo, aunque el usuario puede ver solo dos UIViewController a la vez, mostrar repetidamente el UIViewController no elimina el UIViewController inferior de la jerarquía.
Redimensionando
La nueva apariencia de estilo de tarjeta significa que el UIViewController que se muestra no es tan alto en iOS 13 como en iOS 12:

¡Quiero una pantalla completa!
Una solicitud explícita para mostrar el UIViewController en modo Pantalla completa evitará que se muestre la pantalla de estilo de tarjeta. Sin embargo, esto puede alterar el comportamiento de la aplicación en el iPad. No caiga en la tentación de comprobar el idioma del dispositivo y utilizar un estilo de presentación diferente para iPhone y iPad. Si los últimos años nos han enseñado algo, es que no debemos hacer suposiciones basadas en los tipos de dispositivos o tamaños de pantalla. Si desea que el iPad muestre Página / Hoja de formulario, pero el iPhone tiene Pantalla completa, puede usar UIAdaptivePresentationControllerDelegate
para adaptarse al modo de pantalla completa en condiciones de ancho compacto.
Presentación modal en iPad
Las pantallas que se muestran en el estilo Hoja de formulario permanecen sin cambios en iOS 13:

Hojas de página
Como se señaló anteriormente, el modalPresentationStyle
predeterminado en iOS 13 ahora es una Hoja de página. En iPad, el tamaño del UIViewController en este estilo ha cambiado tanto en orientación vertical como horizontal:


Al igual que en iOS 12, la restricción de "contenido legible" (tamaño de contenido legible original) cambia su tamaño cuando se cambia la categoría de tamaño de contenido (categoría de tamaño de contenido original). El tamaño real parece diferente en iOS 12 y 13 en algunas categorías de tamaño de contenido.
El UIViewController en sí, presentado en el estilo de la Hoja de página, también aumenta en iOS 13 con un aumento en la categoría de tamaño de contenido. Aquí está la categoría "Extra Extra Extra Large" (el tamaño máximo disponible sin incluir tamaños de accesibilidad más grandes):


Otros tipos de presentaciones.
La documentación para modalPresentationStyle
dice:
De forma predeterminada, el UIViewController define el UIModalPresentationAutomatic como una UIModalPresentationPageSheet, pero otros controladores del sistema pueden definir el UIModalPresentationAutomatic de manera diferente.
No estoy 100% seguro de todas las reglas para "el resto de los controladores del sistema", pero descubrí que mostrar un UIViewController con una pantalla dividida sin instalar modalPresentationStyle
ofrece una vista de toda la tarjeta:

Desliza para descartar
Otro cambio importante que afecta tanto al iPhone como al iPad es que las pantallas presentadas de manera modal que no están en modo de pantalla completa (excepto las ventanas emergentes) pueden cerrarse interactivamente deslizando hacia abajo. En este momento, la pantalla de atrás vuelve al modo de pantalla completa:

Tenga en cuenta que en este ejemplo, coloqué la pantalla "Acerca de" en el UINavigationController de la pantalla de configuración. Aunque UINavigationController no mostró su controlador raíz, fue posible el cierre interactivo.
¡No me azotes, por favor!
Si confía en que el usuario haga clic en el botón Finalizar (o un botón similar) o salte a la parte superior de la pila del controlador de navegación para cerrar el UIViewController que se muestra modalmente, el nuevo comportamiento de deslizamiento para cerrar puede interrumpir su aplicación porque su controlador de cierre de pantalla no será ejecutado
Por ejemplo, en mi aplicación Pomodoro Timer Pommie, un usuario puede ir a una pantalla secundaria en la pantalla Configuración y agregar o editar un perfil de temporizador (configuración para períodos de trabajo / descanso para un tipo específico de tarea):

En el caso de Pommie, creo que es normal (y seguro) si el usuario cierra toda la pantalla de configuración con solo deslizar. Los usuarios probablemente esperarán que puedan cerrar la pantalla de una vez, y quiero que mis aplicaciones funcionen correctamente en iOS 13. Sin embargo, creo que en la pantalla "Agregar / Cambiar perfil del temporizador", no puede permitir que el usuario cierre la pantalla deslizando el dedo, ya que existe el riesgo de pérdida de cambio. Es posible que no sea del todo claro para el usuario lo que sucederá después de tal cierre.
Una parte de la solución de este problema es la nueva isModalInPresentation
UIViewController: isModalInPresentation
. De la documentación:
modalInPresentation se establece cuando desea que la pantalla se convierta en modal. Cuando esta opción está habilitada, la presentación evitará el cierre interactivo e ignorará los eventos fuera de los límites del UIViewController hasta que este parámetro se establezca en NO.
Para obtener un comportamiento similar al iOS 12 para mi pantalla de Configuración en iOS 13, podría establecer la propiedad isModalInPresentation
del isModalInPresentation
UINavigationController que se muestra modalmente. Si el usuario intenta deslizar hacia abajo para cerrarlo, la pantalla cambiará un poco, pero resistirá las acciones del usuario y no se cerrará.
La propiedad se puede cambiar en cualquier momento para que pueda, por ejemplo, permitir el cierre si el usuario aún no ha realizado cambios que se perderán si no los ha guardado explícitamente. Pero una vez que se ha realizado el cambio, puede configurar isModalInPresentation
para evitar el cierre deslizando el isModalInPresentation
. Esto obligará al usuario a hacer clic en el botón "Cancelar" o "Guardar".
Detección cercana
Como se señaló anteriormente, algunas aplicaciones pueden necesitar ejecutar algún código cuando el UIViewController modificable se cierra usando los botones Cancelar, Finalizar o Guardar (aparte de simplemente cerrarlo). Por ejemplo, es posible que deba reiniciar el temporizador en el juego o actuar sobre la base de cierta información que el usuario ha cambiado. Este código no se ejecutará si el usuario cierra la pantalla deslizando el dedo. Su botón no está presionado, por lo que no se llamará a su controlador de acción. Esto puede interrumpir el comportamiento de su aplicación.
La forma más fácil de evitar este problema es evitar el cierre interactivo mediante isModalInPresentation. El usuario tendrá que presionar un botón para cerrar el controlador de vista, tal como era antes de iOS 13. Pero hay otra forma ...
iOS 13 agrega algunos nuevos métodos UIAdaptivePresentationControllerDelegate. Permiten que otro objeto (generalmente una pantalla que muestra otra pantalla sea modal) controle si se permite el cierre interactivo (una alternativa al uso de isModalInPresentation
) y recibir información sobre cuándo comienza o termina un cierre interactivo. Estos métodos están bien documentados y se explican claramente en WWDC 2019 224: Modernización de su interfaz de usuario para IOS 13 , a partir del minuto 15. Tenga en cuenta que puede llamar a presentationControllerWillDismiss varias veces si el usuario comienza a deslizar para cerrar, cambia de opinión y luego vuelve a deslizar. En el método presentationControllerDidDismiss
, debe ejecutar código adicional, que se llama cuando se presiona el botón "Cancelar", "Finalizar" o "Guardar" (por supuesto, no necesita cerrar la pantalla que se muestra). No se invocarán estos métodos si UIViewController se cierra mediante programación. Por lo tanto, aún deberá ejecutar su código en el controlador de botones (o en su propio delegado), lo que provoca el cierre incluso cuando trabaja en iOS 13.
Veamos el método de delegado presentationControllerDidAttemptToDismiss
. Se llamará si el usuario intenta deslizar para cerrar, pero isModalInPresentation
ha provocado un bloqueo de bloqueo. En el video con WWDC, se propone mostrar una lista de acciones con la pregunta de si el usuario desea descartar los cambios o guardarlos. Esto parece una muy buena idea si el UIViewController que se muestra tiene los botones Cancelar y Guardar / Listo: cree una nueva nota, edite las propiedades del objeto, etc.
Creo que para un UIViewController anidado en la pila de navegación con los botones Cancelar y Guardar, esto es más complicado. El código para realizar el guardado probablemente esté en el UIViewController, que está un nivel más arriba en la pila, y no en el objeto que implementa el UIAdaptivePresentationControllerDelegate
. Intentar redirigir la selección de un usuario a un objeto que pueda realizar el guardado puede no ser del todo apropiado. En mis propias aplicaciones, creo que bloquearé el cierre de pantallas que requieren una acción explícita de deshacer / guardar si no están en la parte superior de la pila de navegación.
Recursos
El video de WWDC 2019 será el mejor lugar para descubrir qué ha cambiado en iOS 13, qué cambios necesita hacer en sus aplicaciones para que funcionen correctamente al compilar en Xcode 11, y qué cambios puede hacer para mejorarlos para aprovechar los nuevos funciones Aquí hay algunos videos para comenzar:
Conclusión
Hasta ahora, no he encontrado ningún problema con mis aplicaciones creadas en Xcode 10 en iOS 13. La compatibilidad con versiones anteriores realmente funciona aquí. Me sorprendió un poco ver un cambio en la apariencia de una tabla agrupada.
Las compilaciones de Xcode 11 necesitaban algunas correcciones menores para lidiar con los cambios en las representaciones modales discutidas en esta publicación. Probablemente habrá cambios que aún no he descubierto.
¡Pruebe sus presentaciones modales a fondo (especialmente con barras de búsqueda)! Decida si desea permitir que el usuario cierre las pantallas modales con deslizamiento, y use isModalInPresentation
para obtener el comportamiento necesario para evitar la pérdida accidental de datos debido a deslizamiento erróneo. Para una mayor flexibilidad y control, use el UIAdaptivePresentationControllerDelegate
.