Modal Presentation — mod de afișare a ecranului peste contextul curent cu blocarea interacțiunii cu interfața anterioară. În dezvoltarea mobilă, ferestrele modale sunt utilizate pentru sarcini focusate: introducerea datelor, confirmarea acțiunilor, autentificarea și selectarea opțiunilor. Conform Apple HIG, 2025, prezentările modale nu trebuie să ocupe mai mult de 20% din scenariile de navigare în aplicație. În Android, modalitatea este implementată prin DialogFragment, BottomSheet și Activity cu flaguri de lansare specifice.
Principalele puncte
Modal Presentation — este un model de navigare în care un ecran nou apare peste cel curent, blocând temporar interacțiunea cu conținutul părinte. Utilizatorul trebuie să finalizeze explicit sarcina modală (anulare, salvare, închidere) pentru a reveni la starea anterioară.
Modalitatea rezolvă o sarcină cognitivă: concentrează atenția utilizatorului asupra unei singure acțiuni fără a fi distras de restul interfeței. Acest lucru este critic pentru formularele de înregistrare, dialogurile de confirmare, selectarea fișierelor și autentificarea prin servicii terțe. Human Interface Guidelines Apple recomandă utilizarea modalității doar pentru sarcinile care necesită finalizare înainte de a continua lucrul.
Spre deosebire de ferestrele modale web, Modal Presentation mobilă poate fi pe ecran complet (ocupă întregul ecran) sau parțială (Page Sheet, Bottom Sheet). Alegerea tipului depinde de contextul sarcinii și de convențiile platformei. iOS tinde spre Page Sheet pentru majoritatea scenariilor, lăsând Full Screen pentru playere video și editoare foto.
Push Presentation (navigare în stivă) adaugă ecranul în stiva de navigare și afișează automat butonul de înapoi. Utilizatorul poate reveni la ecranul anterior în orice moment. Modal Presentation, dimpotrivă, presupune finalizare explicită: butonul de înapoi fie lipsește, fii închide fereastra modală, nu revine la ecranul anterior.
Principalele diferențe între prezentarea modală și push: Modal Presentation blochează navigarea înapoi fără pierderea datelor, necesită o acțiune pentru închidere (Save, Cancel, Done) și de obicei prezintă o sarcină separată. Push Presentation păstrează ierarhia de navigare, adaugă automat butonul de revenire și este potrivit pentru vizualizarea secvențială a conținutului.
| Caracteristică | Modal Presentation | Push Presentation |
|---|---|---|
| Blocare înapoi | Da, necesită acțiune explicită | Nu, butonul înapoi este întotdeauna disponibil |
| Utilizare tipică | Formulare, autentificare, selecție | Vizualizare detalii, navigare |
| Animație | De jos în sus (iOS), glisare (Android) | De la dreapta la stânga (iOS) |
| Stivă de navigare | Nu se adaugă în stiva principală | Se adaugă în stivă |
În practică, alegerea între Modal și Push depinde de context. Se recomandă utilizarea modalității pentru sarcinile pe care utilizatorul trebuie să le finalizeze înainte de a continua, iar Push — pentru explorarea secvențială a conținutului. Amestecarea modelelor pe același ecran duce la confuzie și înrăutățește UX.
iOS oferă mai multe stiluri de prezentare modală prin enumerarea UIModalPresentationStyle. UIKit suportă .fullScreen (ecran complet), .pageSheet (carte cu margine sus), .formSheet (fereastră centrată pe iPad) și .automatic (selectare de către sistem pe baza contextului). Începând cu iOS 13, stilul implicit a devenit .automatic, care pentru iPhone alege .pageSheet.
Metoda de bază UIKit pentru prezentarea modală — present(_:animated:completion:). Controlerul care apelează metoda devine presentingViewController, iar cel nou — presentedViewController. Închiderea se realizează prin dismiss(animated:completion:). SwiftUI oferă modificatorul .sheet pentru un comportament similar.
Abordarea declarativă SwiftUI utilizează modificatorii .sheet și .fullScreenCover. Primul creează Page Sheet, al doilea — o prezentare modală pe ecran complet. Ambele acceptă un binding la Bool sau un obiect identificabil care controlează vizibilitatea ferestrei modale. Închiderea are loc la setarea binding-ului la false sau apelarea dismiss din environment.
struct ContentView: View {
@State private var showModal = false
var body: some View {
Button("Deschide formularul") {
showModal = true
}
.sheet(isPresented: $showModal) {
RegistrationForm()
}
}
}
struct RegistrationForm: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
Button("Salvează") { dismiss() }
}
}
Android nu are o singură API pentru prezentarea modală ca iOS. În schimb, platforma oferă mai multe mecanisme: DialogFragment pentru ferestre dialog, BottomSheetDialogFragment pentru panouri inferioare și Activity cu flaguri NEW_TASK și CLEAR_TOP pentru ecrane modale. În Jetpack Compose a apărut o componentă unică Dialog pentru toate tipurile de ferestre modale.
DialogFragment — clasa de bază pentru ferestrele modale în Android SDK. Gestionează ciclul de viață al dialogului, procesează rotirea ecranului și salvează starea. Fragmentul se afișează peste Activity fără a bloca stiva de navigare. Închiderea se realizează prin dismiss() sau clic în afara zonei dialogului dacă setCancelable(true).
BottomSheetDialogFragment afișează fereastra modală ca un panou care se ridică de jos. Acest model este popular în Material Design pentru selectarea opțiunilor, partajare și acțiuni rapide. BottomSheet poate avea înălțime fixă sau extensibilă (peek height + full height). În Compose se utilizează ModalBottomSheet din biblioteca Material3.
@Composable
fun ModalScreen(onDismiss: () -> Unit) {
Dialog(onDismissRequest = onDismiss) {
Card(
modifier = Modifier.padding(16.dp)
) {
Column {
Text("Formular modal", style = MaterialTheme.typography.headlineSmall)
Button(onClick = onDismiss) {
Text("Închide")
}
}
}
}
}
Ferestrele modale — un instrument UX puternic, dar utilizarea lor excesivă înrăutățește experiența utilizatorului. Apple HIG și Google Material Design sunt de acord în recomandări: modalitatea trebuie aplicată pentru sarcini focusate și să nu depășească 20% din numărul total de acțiuni de navigare.
Ferestrele modale sunt potrivite pentru scenarii: introducerea datelor (formulare de înregistrare, profil), confirmare (ștergere, trimitere), selecție (selector de dată, manager de fișiere) și autentificare (OAuth, Firebase Auth). Dacă sarcina durează mai puțin de 30 de secunde și necesită blocarea contextului — alegeți modalitatea.
Nu utilizați prezentarea modală pentru: vizualizarea secvențială a conținutului (utilizați Push), afișarea erorilor (utilizați Toast sau Snackbar), reclame și oferte promoționale fără solicitarea explicită a utilizatorului. Material Design recomandă evitarea ferestrelor modale imbricate — acest lucru dezorientează utilizatorul și încalcă ierarhia de navigare.
Pentru ferestrele modale cu câmpuri text, gestionați obligatoriu pierderea focusului tastaturii. La apariția tastaturii, fereastra modală trebuie să se deplaseze în sus pentru ca utilizatorul să vadă textul introdus. UIKeyboardWillShowNotification în iOS și adjustResize în Android rezolvă această problemă.
Să analizăm implementarea prezentării modale pe ambele platforme. Exemplul Swift arată configurarea UIModalPresentationStyle.pageSheet cu delegat pentru gestionarea închiderii. Exemplul Kotlin demonstrează DialogFragment cu layout personalizat și salvare a stării.
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("Fereastra modală închisă")
}
}
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()
}
}
}
Întrebări frecvente
Utilizați Modal Presentation pentru sarcini focusate pe care utilizatorul trebuie să le finalizeze înainte de a continua: formulare, confirmări, autentificare. Push este potrivit pentru vizualizarea secvențială a conținutului, unde utilizatorul poate reveni liber înapoi. Fereastra modală nu trebuie să conțină navigare în interiorul său.
Începând cu iOS 13, stilul implicit .automatic alege .pageSheet pentru iPhone. .pageSheet este potrivit pentru majoritatea scenariilor (formulare, detalii). .fullScreen — pentru conținut media (video, editoare foto). .formSheet — pentru aplicațiile iPad unde este necesară o fereastră centrată.
Jetpack Compose oferă componenta Dialog pentru ferestre modale simple și ModalBottomSheet pentru panouri inferioare. Dialog acceptă onDismissRequest și conținut în stil Compose. Pentru salvarea stării, utilizați rememberSaveable în interiorul dialogului.
Apple HIG și Material Design nu recomandă ferestrele modale imbricate. Dacă utilizatorul deschide o fereastră modală peste altă fereastră modală, pierde contextul și se poate încurca în ierarhie. În loc de imbricare, utilizați Step Indicator sau modelul Wizard cu o singură fereastră modală.
Utilizați UIAdaptivePresentationControllerDelegate în iOS (metoda presentationControllerShouldDismiss) sau OnBackPressedDispatcher în Android. La existența datelor nesalvate, afișați un AlertDialog cu opțiunile: salvare, anulare modificări, rămânere pe ecran. Acest lucru previne pierderea accidentală a datelor de către utilizator.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și