Presentación Modal es una forma de mostrar una pantalla sobre el contexto actual, bloqueando la interacción con la interfaz anterior. En el desarrollo móvil, las ventanas modales se utilizan para tareas enfocadas: ingreso de datos, confirmación de acciones, autorización y selección de opciones. Según Apple HIG, 2025, las presentaciones modales no deben ocupar más del 20% de los escenarios de navegación en una aplicación. En Android, la modalidad se implementa mediante DialogFragment, BottomSheet y Activity con indicadores de lanzamiento específicos.
Puntos clave
Presentación Modal es un patrón de navegación en el que una nueva pantalla aparece sobre la actual, bloqueando temporalmente la interacción con el contenido principal. El usuario debe completar explícitamente la tarea modal (cancelar, guardar, cerrar) para volver al estado anterior.
La modalidad resuelve una tarea cognitiva: enfoca la atención del usuario en una sola acción sin distracción del resto de la interfaz. Esto es críticamente importante para formularios de registro, diálogos de confirmación, selección de archivos y autorización a través de servicios de terceros. Las Human Interface Guidelines de Apple recomiendan usar la modalidad solo para tareas que requieren finalización antes de continuar.
A diferencia de las ventanas modales web, la Presentación Modal móvil puede ser de pantalla completa (ocupando toda la pantalla) o parcial (Page Sheet, Bottom Sheet). La elección del tipo depende del contexto de la tarea y las convenciones de la plataforma. iOS tiende a usar Page Sheet para la mayoría de los escenarios, dejando Full Screen para reproductores de video y editores de fotos.
Push Presentation (navegación por pila) agrega una pantalla a la pila de navegación y muestra automáticamente un botón de retroceso. El usuario puede volver a la pantalla anterior en cualquier momento. La Presentación Modal, por el contrario, requiere una finalización explícita: el botón de retroceso está ausente o cierra la ventana modal en lugar de regresar a la pantalla anterior.
Las principales diferencias entre la presentación modal y push: Presentación Modal bloquea la navegación hacia atrás sin pérdida de datos, requiere una acción para cerrar (Save, Cancel, Done) y generalmente representa una tarea separada. Push Presentation conserva la jerarquía de navegación, agrega automáticamente un botón de retroceso y es adecuada para la visualización secuencial de contenido.
| Característica | Presentación Modal | Push Presentation |
|---|---|---|
| Bloqueo de retroceso | Sí, requiere acción explícita | No, el botón de retroceso siempre está disponible |
| Uso típico | Formularios, autorización, selección | Vista detallada, navegación |
| Animación | De abajo arriba (iOS), deslizar (Android) | De derecha a izquierda (iOS) |
| Pila de navegación | No se agrega a la pila principal | Se agrega a la pila |
En la práctica, la elección entre Modal y Push depende del contexto. Se recomienda usar la modalidad para tareas que el usuario debe completar antes de continuar, y Push para la exploración secuencial de contenido. Mezclar patrones en la misma pantalla causa confusión y degrada la experiencia de usuario.
iOS ofrece varios estilos de presentación modal a través de la enumeración UIModalPresentationStyle. UIKit admite .fullScreen (pantalla completa), .pageSheet (tarjeta con margen superior), .formSheet (ventana centrada en iPad) y .automatic (el sistema elige según el contexto). Desde iOS 13, el estilo predeterminado es .automatic, que selecciona .pageSheet para iPhone.
El método básico de UIKit para la presentación modal es present(_:animated:completion:). El controlador que llama al método se convierte en presentingViewController, y el nuevo en presentedViewController. El cierre se realiza mediante dismiss(animated:completion:). SwiftUI proporciona el modificador .sheet para un comportamiento similar.
El enfoque declarativo de SwiftUI utiliza los modificadores .sheet y .fullScreenCover. El primero crea un Page Sheet, el segundo una presentación modal de pantalla completa. Ambos aceptan un binding a un Bool o un objeto identificable que controla la visibilidad de la ventana modal. El cierre ocurre cuando el binding se establece en false o al llamar a dismiss desde el entorno.
struct ContentView: View {
@State private var showModal = false
var body: some View {
Button("Abrir formulario") {
showModal = true
}
.sheet(isPresented: $showModal) {
RegistrationForm()
}
}
}
struct RegistrationForm: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
Button("Guardar") { dismiss() }
}
}
Android no tiene una API única para la presentación modal como iOS. En su lugar, la plataforma ofrece varios mecanismos: DialogFragment para ventanas de diálogo, BottomSheetDialogFragment para paneles inferiores y Activity con indicadores NEW_TASK y CLEAR_TOP para pantallas modales. Jetpack Compose introdujo un componente Dialog unificado para todos los tipos de ventanas modales.
DialogFragment es la clase base para ventanas modales en el SDK de Android. Gestiona el ciclo de vida del diálogo, maneja la rotación de pantalla y guarda el estado. El fragmento se muestra sobre la Activity sin bloquear la pila de navegación. El cierre se realiza mediante dismiss() o tocando fuera del área del diálogo si setCancelable(true).
BottomSheetDialogFragment muestra una ventana modal como un panel que se eleva desde la parte inferior. Este patrón es popular en Material Design para selección de opciones, uso compartido y acciones rápidas. El BottomSheet puede tener altura fija o expandible (altura de vista previa + altura completa). En Compose se utiliza ModalBottomSheet de la biblioteca Material3.
@Composable
fun ModalScreen(onDismiss: () -> Unit) {
Dialog(onDismissRequest = onDismiss) {
Card(
modifier = Modifier.padding(16.dp)
) {
Column {
Text("Formulario modal", style = MaterialTheme.typography.headlineSmall)
Button(onClick = onDismiss) {
Text("Cerrar")
}
}
}
}
}
Las ventanas modales son una herramienta potente de UX, pero su uso excesivo degrada la experiencia del usuario. Apple HIG y Google Material Design coinciden en las recomendaciones: la modalidad debe aplicarse para tareas enfocadas y no superar el 20% del total de acciones de navegación.
Las ventanas modales son adecuadas para escenarios: ingreso de datos (formularios de registro, perfiles), confirmación (eliminación, envío), selección (selector de fecha, administrador de archivos) y autorización (OAuth, Firebase Auth). Si la tarea toma menos de 30 segundos y requiere bloqueo de contexto, elija la modalidad.
No use la presentación modal para: visualización secuencial de contenido (use Push), visualización de errores (use Toast o Snackbar), anuncios y ofertas promocionales sin solicitud explícita del usuario. Material Design recomienda evitar ventanas modales anidadas, ya que desorientan al usuario y alteran la jerarquía de navegación.
Para ventanas modales con campos de texto, asegúrese de manejar la pérdida de enfoque del teclado. Cuando aparece el teclado, la ventana modal debe desplazarse hacia arriba para que el usuario vea el texto que está ingresando. UIKeyboardWillShowNotification en iOS y adjustResize en Android resuelven esta tarea.
Veamos la implementación de la presentación modal en ambas plataformas. El ejemplo en Swift muestra la configuración de UIModalPresentationStyle.pageSheet con un delegado para manejar el cierre. El ejemplo en Kotlin demuestra DialogFragment con un diseño personalizado y conservación del estado.
let modalVC = ModalViewController()
modalVC.modalPresentationStyle = .pageSheet
if let sheet = modalVC.sheetPresentationController {
sheet.detents = [.medium(), .large()]
sheet.prefersGrabberVisible = true
}
modalVC.presentationController?.delegate = self
present(modalVC, animated: true)
// MARK: - UIAdaptivePresentationControllerDelegate
extension ViewController: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
print("Modal cerrado")
}
}
class ModalDialogFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_modal, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById<Button>(R.id.closeButton).setOnClickListener {
dismiss()
}
}
}
Preguntas frecuentes
Use Presentación Modal para tareas enfocadas que el usuario debe completar antes de continuar: formularios, confirmaciones, autorización. Push es adecuado para la visualización secuencial de contenido donde el usuario puede navegar libremente hacia atrás. Una ventana modal no debe contener navegación dentro de sí misma.
Desde iOS 13, el estilo predeterminado .automatic selecciona .pageSheet para iPhone. .pageSheet es adecuado para la mayoría de los escenarios (formularios, detalles). .fullScreen es para contenido multimedia (video, editores de fotos). .formSheet es para aplicaciones de iPad que necesitan una ventana centrada.
Jetpack Compose proporciona el componente Dialog para ventanas modales simples y ModalBottomSheet para paneles inferiores. Dialog acepta onDismissRequest y contenido en estilo Compose. Use rememberSaveable dentro del diálogo para conservar el estado.
Apple HIG y Material Design no recomiendan ventanas modales anidadas. Si un usuario abre una ventana modal sobre otra ventana modal, pierde el contexto y puede confundirse con la jerarquía. En lugar de anidar, use un Indicador de Paso o un patrón de Asistente con una sola ventana modal.
Use UIAdaptivePresentationControllerDelegate en iOS (método presentationControllerShouldDismiss) o OnBackPressedDispatcher en Android. Cuando haya cambios no guardados, muestre un AlertDialog con opciones: guardar, descartar cambios o permanecer en la pantalla. Esto evita la pérdida accidental de datos por parte del usuario.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también