Modal Presentation — روشی برای نمایش صفحه روی زمینه فعلی با مسدود کردن تعامل با رابط قبلی. در توسعه موبایل از پنجرههای Modal برای کارهای متمرکز استفاده میشود: ورود داده، تأیید اقدامات، احراز هویت و انتخاب گزینهها. بر اساس Apple HIG, 2025، ارائههای Modal نباید بیش از 20% سناریوهای ناوبری در برنامه را تشکیل دهند. در Android Modal از طریق DialogFragment، BottomSheet و Activity با پرچمهای launch مشخص پیادهسازی میشود.
نکات اصلی
Modal Presentation — الگویی از ناوبری است که در آن صفحه جدید روی صفحه فعلی ظاهر میشود و به طور موقت تعامل با محتوای والد را مسدود میکند. کاربر باید صریحاً کار Modal را تمام کند (لغو، ذخیره، بستن) تا به حالت قبلی بازگردد.
Modal بودن یک مسئله شناختی را حل میکند: توجه کاربر را روی یک عمل متمرکز میکند بدون اینکه توسط بقیه رابط پرت شود. این برای فرمهای ثبت نام، دیالوگهای تأیید، انتخاب فایل و احراز هویت از طریق سرویسهای شخص ثالث حیاتی است. Human Interface Guidelines اپل توصیه میکند Modal را فقط برای کارهایی استفاده کنید که برای ادامه کار نیاز به تکمیل دارند.
برخلاف پنجرههای Modal وب، Modal Presentation موبایل میتواند تمام صفحه (کل صفحه را اشغال کند) یا جزئی (Page Sheet، Bottom Sheet) باشد. انتخاب نوع به زمینه کار و قراردادهای پلتفرم بستگی دارد. iOS برای بیشتر سناریوها به Page Sheet تمایل دارد و Full Screen را برای پخشکنندههای ویدیو و ویرایشگرهای عکس نگه میدارد.
Push Presentation (ناوبری پشتهای) صفحه را به پشته ناوبری اضافه میکند و به طور خودکار دکمه بازگشت را نشان میدهد. کاربر میتواند در هر لحظه به صفحه قبلی بازگردد. Modal Presentation، برعکس، نیاز به پایان صریح دارد: دکمه بازگشت یا وجود ندارد یا پنجره Modal را میبندد، نه اینکه به صفحه قبلی بازگردد.
تفاوتهای اصلی بین ارائه Modal و Push: Modal Presentation ناوبری به عقب را بدون از دست دادن داده مسدود میکند، برای بسته شدن نیاز به عمل دارد (Save، Cancel، Done) و معمولاً یک کار جداگانه را نشان میدهد. Push Presentation سلسله مراتب ناوبری را حفظ میکند، به طور خودکار دکمه بازگشت را اضافه میکند و برای مشاهده متوالی محتوا مناسب است.
| ویژگی | Modal Presentation | Push Presentation |
|---|---|---|
| مسدود کردن بازگشت | بله، نیاز به عمل صریح دارد | خیر، دکمه بازگشت همیشه در دسترس است |
| استفاده معمول | فرمها، احراز هویت، انتخاب | مشاهده جزئیات، ناوبری |
| انیمیشن | از پایین به بالا (iOS)، اسلاید (Android) | از راست به چپ (iOS) |
| پشته ناوبری | به پشته اصلی اضافه نمیشود | به پشته اضافه میشود |
در عمل، انتخاب بین Modal و Push به زمینه بستگی دارد. توصیه میشود از Modal برای کارهایی استفاده کنید که کاربر باید قبل از ادامه تکمیل کند، و از Push برای بررسی متوالی محتوا. ترکیب الگوها در یک صفحه باعث سردرگمی میشود و UX را بدتر میکند.
iOS چندین سبک ارائه Modal را از طریق enum UIModalPresentationStyle ارائه میدهد. UIKit از .fullScreen (تمام صفحه)، .pageSheet (کارت با فاصله از بالا)، .formSheet (پنجره متمرکز در iPad) و .automatic (انتخاب توسط سیستم بر اساس زمینه) پشتیبانی میکند. از iOS 13، سبک پیشفرض .automatic شده است که برای iPhone .pageSheet را انتخاب میکند.
روش پایه UIKit برای ارائه Modal — present(_:animated:completion:). کنترلکنندهای که متد را فراخوانی میکند presentingViewController میشود و کنترلکننده جدید presentedViewController میشود. بسته شدن از طریق dismiss(animated:completion:) انجام میشود. SwiftUI اصلاحکننده .sheet را برای رفتار مشابه فراهم میکند.
رویکرد اعلانی SwiftUI از اصلاحکنندههای .sheet و .fullScreenCover استفاده میکند. اولی Page Sheet ایجاد میکند، دومی — ارائه Modal تمام صفحه. هر دو یک binding به Bool یا یک شیء قابل شناسایی میپذیرند که visibility پنجره Modal را کنترل میکند. بسته شدن با تنظیم 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 مانند iOS یک API واحد برای ارائه Modal ندارد. در عوض، پلتفرم چندین مکانیسم ارائه میدهد: DialogFragment برای پنجرههای دیالوگ، BottomSheetDialogFragment برای پنلهای پایین و Activity با پرچمهای NEW_TASK و CLEAR_TOP برای صفحات Modal. در Jetpack Compose یک کامپوننت واحد Dialog برای همه انواع پنجرههای Modal ظاهر شده است.
DialogFragment — کلاس پایه برای پنجرههای Modal در Android SDK. این کلاس چرخه زندگی دیالوگ را مدیریت میکند، چرخش صفحه را پردازش میکند و وضعیت را ذخیره میکند. Fragment بدون مسدود کردن پشته ناوبری روی Activity نمایش داده میشود. بسته شدن از طریق dismiss() یا کلیک خارج از ناحیه دیالوگ در صورتی که setCancelable(true) باشد انجام میشود.
BottomSheetDialogFragment پنجره Modal را به صورت پنلی که از پایین بالا میآید نمایش میدهد. این الگو در 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("فرم Modal", style = MaterialTheme.typography.headlineSmall)
Button(onClick = onDismiss) {
Text("بستن")
}
}
}
}
}
پنجرههای Modal — ابزار قدرتمند UX، اما استفاده بیش از حد از آنها تجربه کاربری را بدتر میکند. Apple HIG و Google Material Design در توصیهها همنظر هستند: Modal باید برای کارهای متمرکز استفاده شود و از 20% کل اقدامات ناوبری تجاوز نکند.
پنجرههای Modal برای سناریوهای زیر مناسب هستند: ورود داده (فرمهای ثبت نام، پروفایل)، تأیید (حذف، ارسال)، انتخاب (انتخابگر تاریخ، مدیر فایل) و احراز هویت (OAuth، Firebase Auth). اگر کار کمتر از 30 ثانیه طول میکشد و نیاز به مسدود کردن زمینه دارد — Modal را انتخاب کنید.
از ارائه Modal استفاده نکنید برای: مشاهده متوالی محتوا (از Push استفاده کنید)، نمایش خطاها (از Toast یا Snackbar استفاده کنید)، تبلیغات و پیشنهادات تبلیغاتی بدون درخواست صریح کاربر. Material Design توصیه میکند از پنجرههای Modal تو در تو خودداری کنید — این کاربر را سردرگم میکند و سلسله مراتب ناوبری را نقض میکند.
برای پنجرههای Modal با فیلدهای متنی، حتماً از دست رفتن focus صفحه کلید را مدیریت کنید. هنگام ظاهر شدن صفحه کلید، پنجره Modal باید به بالا حرکت کند تا کاربر متن وارد شده را ببیند. UIKeyboardWillShowNotification در iOS و adjustResize در Android این مشکل را حل میکنند.
بیایید پیادهسازی ارائه Modal را در هر دو پلتفرم بررسی کنیم. نمونه Swift تنظیم UIModalPresentationStyle.pageSheet با delegate برای مدیریت بسته شدن را نشان میدهد. نمونه 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("Modal بسته شد")
}
}
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 برای مشاهده متوالی محتوا مناسب است، جایی که کاربر میتواند آزادانه به عقب بازگردد. پنجره Modal نباید داخل خود ناوبری داشته باشد.
از iOS 13، سبک پیشفرض .automatic برای iPhone .pageSheet را انتخاب میکند. .pageSheet برای بیشتر سناریوها مناسب است (فرمها، جزئیات). .fullScreen — برای محتوای چندرسانهای (ویدئو، ویرایشگرهای عکس). .formSheet — برای برنامههای iPad که نیاز به پنجره متمرکز دارند.
Jetpack Compose کامپوننت Dialog را برای پنجرههای Modal ساده و ModalBottomSheet را برای پنلهای پایین فراهم میکند. Dialog onDismissRequest و محتوا به سبک Compose را میپذیرد. برای ذخیره وضعیت از rememberSaveable داخل دیالوگ استفاده کنید.
Apple HIG و Material Design پنجرههای Modal تو در تو را توصیه نمیکنند. اگر کاربر یک پنجره Modal را روی پنجره Modal دیگر باز کند، زمینه را از دست میدهد و ممکن است در سلسله مراتب سردرگم شود. به جای تو در تو کردن از Step Indicator یا الگوی Wizard با یک پنجره Modal استفاده کنید.
از UIAdaptivePresentationControllerDelegate در iOS (متد presentationControllerShouldDismiss) یا OnBackPressedDispatcher در Android استفاده کنید. در صورت وجود دادههای ذخیره نشده، AlertDialog با گزینههای: ذخیره، لغو تغییرات، ماندن در صفحه نمایش دهید. این کار از از دست دادن تصادفی داده توسط کاربر جلوگیری میکند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید