Modal Presentation — начин приказивања екрана изнад тренутног контекста са блокирањем интеракције са претходним интерфејсом. У мобилном развоју, модални прозори се користе за фокусиране задатке: унос података, потврђивање радњи, ауторизација и избор опција. Према Apple HIG, 2025, модалне презентације не би требало да заузимају више од 20% навигационих сценарија у апликацији. У Android-у модалност се реализује кроз DialogFragment, BottomSheet и Activity са одређеним launch-флаговима.
Главне ствари
Modal Presentation — је образац навигације при којем се нови екран појављује изнад тренутног, привремено блокирајући интеракцију са родитељским садржајем. Корисник мора експлицитно да заврши модални задатак (отказивање, чување, затварање) да би се вратио у претходно стање.
Модалност решава когнитивни задатак: фокусира пажњу корисника на једну радњу без ометања остатком интерфејса. Ово је критично за формуларе за регистрацију, дијалоге за потврду, избор датотека и ауторизацију преко услуга трећих страна. Human Interface Guidelines компаније Apple препоручују коришћење модалности само за задатке који захтевају завршетак пре наставка рада.
За разлику од веб модалних прозора, мобилна Modal Presentation може бити преко целог екрана (заузима цео екран) или делимична (Page Sheet, Bottom Sheet). Избор типа зависи од контекста задатка и платформских конвенција. iOS тежи ка Page Sheet-у за већину сценарија, остављајући Full Screen за видео плејере и фото едиторе.
Push Presentation (стек навигација) додаје екран у навигациони стек и аутоматски приказује дугме за назад. Корисник се може вратити на претходни екран у било ком тренутку. Modal Presentation, напротив, подразумева експлицитан завршетак: дугме за назад или не постоји, или затвара модални прозор, а не враћа на претходни екран.
Главне разлике између модалне и push презентације: Modal Presentation блокира навигацију уназад без губитка података, захтева радњу за затварање (Save, Cancel, Done) и обично представља засебан задатак. Push Presentation чува хијерархију навигације, аутоматски додаје дугме за повратак и погодна је за секвенцијални преглед садржаја.
| Карактеристика | Modal Presentation | Push Presentation |
|---|---|---|
| Блокирање назад | Да, захтева експлицитну радњу | Не, дугме за назад увек доступно |
| Типична употреба | Формулари, ауторизација, избор | Детаљан преглед, навигација |
| Анимација | Одоздо нагоре (iOS), слајд (Android) | Здесна налево (iOS) |
| Стек навигације | Не додаје се у главни стек | Додаје се у стек |
У пракси, избор између Modal и Push зависи од контекста. Препоручује се коришћење модалности за задатке које корисник мора да заврши пре наставка, а Push — за секвенцијално истраживање садржаја. Мешање образаца на истом екрану доводи до конфузије и погоршава UX.
iOS нуди неколико стилова модалне презентације кроз енумерацију UIModalPresentationStyle. UIKit подржава .fullScreen (пуни екран), .pageSheet (картица са размаком одозго), .formSheet (центрирани прозор на iPad-у) и .automatic (избор од стране система на основу контекста). Од iOS 13, подразумевани стил је постао .automatic, који за iPhone бира .pageSheet.
Основни метод UIKit-а за модалну презентацију — present(_:animated:completion:). Контролер који позива метод постаје presentingViewController, а нови — presentedViewController. Затварање се врши кроз dismiss(animated:completion:). SwiftUI пружа модификатор .sheet за слично понашање.
Декларативни приступ SwiftUI користи модификаторе .sheet и .fullScreenCover. Први креира Page Sheet, други — модалну презентацију преко целог екрана. Оба прихватају binding на Bool или идентификовани објекат који управља видљивошћу модалног прозора. Затварање се дешава постављањем binding-а на false или позивом dismiss из environment-а.
struct ContentView: View {
@State private var showModal = false
var body: some View {
Button("Отвори формулар") {
showModal = true
}
.sheet(isPresented: $showModal) {
RegistrationForm()
}
}
}
struct RegistrationForm: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
Button("Сачувај") { dismiss() }
}
}
Android нема јединствени API за модалну презентацију као iOS. Уместо тога, платформа нуди неколико механизама: DialogFragment за дијалог прозоре, BottomSheetDialogFragment за доње панеле и Activity са флаговима NEW_TASK и CLEAR_TOP за модалне екране. У Jetpack Compose-у се појавила јединствена компонента Dialog за све врсте модалних прозора.
DialogFragment — основна класа за модалне прозоре у Android SDK-у. Управља животним циклусом дијалога, обрађује ротацију екрана и чува стање. Фрагмент се приказује изнад Activity без блокирања навигационог стека. Затварање се врши кроз dismiss() или клик изван области дијалога ако је setCancelable(true).
BottomSheetDialogFragment приказује модални прозор као панел који се подиже одоздо. Овај образац је популаран у Material Design-у за избор опција, дељење и брзе радње. BottomSheet може бити фиксне висине или проширив (peek height + full height). У Compose-у се користи ModalBottomSheet из библиотеке Material3.
@Composable
fun ModalScreen(onDismiss: () -> Unit) {
Dialog(onDismissRequest = onDismiss) {
Card(
modifier = Modifier.padding(16.dp)
) {
Column {
Text("Модални формулар", style = MaterialTheme.typography.headlineSmall)
Button(onClick = onDismiss) {
Text("Затвори")
}
}
}
}
}
Модални прозори — моћан UX алат, али њихово прекомерно коришћење погоршава корисничко искуство. Apple HIG и Google Material Design се слажу у препорукама: модалност треба примењивати за фокусиране задатке и не прелазити 20% укупног броја навигационих радњи.
Модални прозори су погодни за сценарије: унос података (формулари за регистрацију, профил), потврда (брисање, слање), избор (бирач датума, менаџер датотека) и ауторизација (OAuth, Firebase Auth). Ако задатак траје мање од 30 секунди и захтева блокирање контекста — изаберите модалност.
Немојте користити модалну презентацију за: секвенцијални преглед садржаја (користите Push), приказивање грешака (користите Toast или Snackbar), рекламе и промо понуде без експлицитног захтева корисника. Material Design препоручује избегавање угнежђених модалних прозора — то дезоријентише корисника и нарушава хијерархију навигације.
За модалне прозоре са текстуалним пољима обавезно обрађујте губитак фокуса тастатуре. При појави тастатуре, модални прозор треба да се помери нагоре како би корисник видео текст који уноси. UIKeyboardWillShowNotification у iOS-у и adjustResize у Android-у решавају овај проблем.
Размотримо имплементацију модалне презентације на обе платформе. Пример у Swift-у показује подешавање UIModalPresentationStyle.pageSheet са делегатом за обраду затварања. Пример у Kotlin-у демонстрира DialogFragment са прилагођеним layout-ом и чувањем стања.
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("Модални прозор затворен")
}
}
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()
}
}
}
Често постављана питања
Користите Modal Presentation за фокусиране задатке које корисник мора да заврши пре наставка: формулари, потврде, ауторизација. Push је погодан за секвенцијални преглед садржаја, где корисник може слободно да се враћа назад. Модални прозор не треба да садржи навигацију унутар себе.
Од iOS 13, подразумевани стил .automatic бира .pageSheet за iPhone. .pageSheet је погодан за већину сценарија (формулари, детаљи). .fullScreen — за медијски садржај (видео, фото едитори). .formSheet — за iPad апликације где је потребан центрирани прозор.
Jetpack Compose пружа компоненту Dialog за једноставне модалне прозоре и ModalBottomSheet за доње панеле. Dialog прихвата onDismissRequest и садржај у Compose стилу. За чување стања користите rememberSaveable унутар дијалога.
Apple HIG и Material Design не препоручују угнежђене модалне прозоре. Ако корисник отвори модални прозор изнад другог модалног прозора, губи контекст и може се збунити у хијерархији. Уместо угнежђивања користите Step Indicator или Wizard образац са једним модалним прозором.
Користите UIAdaptivePresentationControllerDelegate у iOS-у (метод presentationControllerShouldDismiss) или OnBackPressedDispatcher у Android-у. У случају несачуваних података прикажите AlertDialog са опцијама: сачувај, откажи измене, остани на екрану. Ово спречава случајни губитак података од стране корисника.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође