Presentazione Modale è un modo di visualizzare una schermata sopra il contesto corrente, bloccando l’interazione con l’interfaccia precedente. Nello sviluppo mobile, le finestre modali vengono utilizzate per attività focalizzate: inserimento dati, conferma azioni, autorizzazione e selezione di opzioni. Secondo Apple HIG, 2025, le presentazioni modali non dovrebbero occupare più del 20% degli scenari di navigazione in un’applicazione. In Android, la modalità viene implementata tramite DialogFragment, BottomSheet e Activity con flag di avvio specifici.
Punti chiave
Presentazione Modale è un pattern di navigazione in cui una nuova schermata appare sopra quella corrente, bloccando temporaneamente l’interazione con il contenuto principale. L’utente deve completare esplicitamente l’attività modale (annullare, salvare, chiudere) per tornare allo stato precedente.
La modalità risolve un compito cognitivo: concentra l’attenzione dell’utente su una singola azione senza distrazione dal resto dell’interfaccia. Questo è criticamente importante per i moduli di registrazione, i dialoghi di conferma, la selezione di file e l’autorizzazione tramite servizi di terze parti. Le Human Interface Guidelines di Apple raccomandano di usare la modalità solo per attività che richiedono completamento prima di procedere.
A differenza delle finestre modali web, la Presentazione Modale mobile può essere a schermo intero (occupando l’intero schermo) o parziale (Page Sheet, Bottom Sheet). La scelta del tipo dipende dal contesto dell’attività e dalle convenzioni della piattaforma. iOS tende a utilizzare Page Sheet per la maggior parte degli scenari, lasciando Full Screen per lettori video e editor fotografici.
Push Presentation (navigazione a pila) aggiunge una schermata alla pila di navigazione e mostra automaticamente un pulsante Indietro. L’utente può tornare alla schermata precedente in qualsiasi momento. La Presentazione Modale, al contrario, richiede un completamento esplicito: il pulsante Indietro è assente o chiude la finestra modale anziché tornare alla schermata precedente.
Le principali differenze tra presentazione modale e push: Presentazione Modale blocca la navigazione all’indietro senza perdita di dati, richiede un’azione per chiudere (Save, Cancel, Done) e di solito rappresenta un’attività separata. Push Presentation preserva la gerarchia di navigazione, aggiunge automaticamente un pulsante Indietro ed è adatto per la visualizzazione sequenziale di contenuti.
| Caratteristica | Presentazione Modale | Push Presentation |
|---|---|---|
| Blocco Indietro | Sì, richiede azione esplicita | No, pulsante Indietro sempre disponibile |
| Utilizzo tipico | Moduli, autorizzazione, selezione | Vista dettagliata, navigazione |
| Animazione | Dal basso verso l’alto (iOS), scorrimento (Android) | Da destra a sinistra (iOS) |
| Pila di navigazione | Non aggiunta alla pila principale | Aggiunta alla pila |
In pratica, la scelta tra Modal e Push dipende dal contesto. Si raccomanda di utilizzare la modalità per attività che l’utente deve completare prima di continuare, e Push per l’esplorazione sequenziale di contenuti. Mischiare pattern sulla stessa schermata causa confusione e degrada l’esperienza utente.
iOS offre diversi stili di presentazione modale attraverso l’enumerazione UIModalPresentationStyle. UIKit supporta .fullScreen (schermo intero), .pageSheet (scheda con margine superiore), .formSheet (finestra centrata su iPad) e .automatic (il sistema sceglie in base al contesto). Da iOS 13, lo stile predefinito è .automatic, che seleziona .pageSheet per iPhone.
Il metodo UIKit di base per la presentazione modale è present(_:animated:completion:). Il controller che chiama il metodo diventa presentingViewController, e il nuovo controller diventa presentedViewController. La chiusura viene effettuata tramite dismiss(animated:completion:). SwiftUI fornisce il modificatore .sheet per un comportamento simile.
L’approccio dichiarativo di SwiftUI utilizza i modificatori .sheet e .fullScreenCover. Il primo crea un Page Sheet, il secondo una presentazione modale a schermo intero. Entrambi accettano un binding a un Bool o un oggetto identificabile che controlla la visibilità della finestra modale. La chiusura avviene quando il binding viene impostato su false o chiamando dismiss dall’ambiente.
struct ContentView: View {
@State private var showModal = false
var body: some View {
Button("Apri modulo") {
showModal = true
}
.sheet(isPresented: $showModal) {
RegistrationForm()
}
}
}
struct RegistrationForm: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
Button("Salva") { dismiss() }
}
}
Android non ha una singola API per la presentazione modale come iOS. Invece, la piattaforma offre diversi meccanismi: DialogFragment per finestre di dialogo, BottomSheetDialogFragment per pannelli inferiori e Activity con flag NEW_TASK e CLEAR_TOP per schermate modali. Jetpack Compose ha introdotto un componente Dialog unificato per tutti i tipi di finestre modali.
DialogFragment è la classe base per finestre modali nell’SDK Android. Gestisce il ciclo di vita del dialogo, gestisce la rotazione dello schermo e salva lo stato. Il fragment viene visualizzato sopra l’Activity senza bloccare la pila di navigazione. La chiusura viene effettuata tramite dismiss() o toccando fuori dall’area del dialogo se setCancelable(true).
BottomSheetDialogFragment visualizza una finestra modale come pannello che si solleva dal basso. Questo pattern è popolare in Material Design per la selezione di opzioni, la condivisione e le azioni rapide. Il BottomSheet può essere di altezza fissa o espandibile (altezza di anteprima + altezza completa). In Compose viene utilizzato ModalBottomSheet della libreria Material3.
@Composable
fun ModalScreen(onDismiss: () -> Unit) {
Dialog(onDismissRequest = onDismiss) {
Card(
modifier = Modifier.padding(16.dp)
) {
Column {
Text("Modulo modale", style = MaterialTheme.typography.headlineSmall)
Button(onClick = onDismiss) {
Text("Chiudi")
}
}
}
}
}
Le finestre modali sono un potente strumento UX, ma il loro uso eccessivo degrada l’esperienza utente. Apple HIG e Google Material Design concordano sulle raccomandazioni: la modalità dovrebbe essere utilizzata per attività focalizzate e non superare il 20% del totale delle azioni di navigazione.
Le finestre modali sono adatte per scenari: inserimento dati (moduli di registrazione, profili), conferma (eliminazione, invio), selezione (selettore data, gestore file) e autorizzazione (OAuth, Firebase Auth). Se l’attività richiede meno di 30 secondi e necessita di blocco del contesto, scegliere la modalità.
Non utilizzare la presentazione modale per: visualizzazione sequenziale di contenuti (usare Push), visualizzazione di errori (usare Toast o Snackbar), pubblicità e offerte promozionali senza richiesta esplicita dell’utente. Material Design raccomanda di evitare finestre modali annidate — questo disorienta l’utente e interrompe la gerarchia di navigazione.
Per finestre modali con campi di testo, assicurarsi di gestire la perdita di focus della tastiera. Quando la tastiera appare, la finestra modale dovrebbe spostarsi verso l’alto in modo che l’utente veda il testo inserito. UIKeyboardWillShowNotification in iOS e adjustResize in Android risolvono questo compito.
Vediamo l’implementazione della presentazione modale su entrambe le piattaforme. L’esempio in Swift mostra la configurazione di UIModalPresentationStyle.pageSheet con un delegato per gestire la chiusura. L’esempio in Kotlin mostra DialogFragment con un layout personalizzato e conservazione dello stato.
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("Modale chiuso")
}
}
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()
}
}
}
Domande frequenti
Utilizzare la Presentazione Modale per attività focalizzate che l’utente deve completare prima di continuare: moduli, conferme, autorizzazione. Push è adatto per la visualizzazione sequenziale di contenuti dove l’utente può tornare liberamente indietro. Una finestra modale non dovrebbe contenere navigazione al suo interno.
Da iOS 13, lo stile predefinito .automatic seleziona .pageSheet per iPhone. .pageSheet è adatto per la maggior parte degli scenari (moduli, dettagli). .fullScreen è per contenuti multimediali (video, editor fotografici). .formSheet è per app iPad che necessitano di una finestra centrata.
Jetpack Compose fornisce il componente Dialog per finestre modali semplici e ModalBottomSheet per pannelli inferiori. Dialog accetta onDismissRequest e contenuto in stile Compose. Utilizzare rememberSaveable all’interno del dialogo per la conservazione dello stato.
Apple HIG e Material Design non raccomandano finestre modali annidate. Se un utente apre una finestra modale sopra un’altra finestra modale, perde il contesto e può confondersi sulla gerarchia. Invece dell’annidamento, utilizzare un Indicatore di Passaggio o un pattern di Procedura Guidata con una singola finestra modale.
Utilizzare UIAdaptivePresentationControllerDelegate in iOS (metodo presentationControllerShouldDismiss) o OnBackPressedDispatcher in Android. In presenza di modifiche non salvate, mostrare un AlertDialog con opzioni: salvare, annullare le modifiche o rimanere sulla schermata. Ciò previene la perdita accidentale di dati da parte dell’utente.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche