العرض المشروط هو طريقة لعرض شاشة فوق السياق الحالي مع حظر التفاعل مع الواجهة السابقة. في تطوير التطبيقات المحمولة، تُستخدم النوافذ المشروطة للمهام المركزة: إدخال البيانات، تأكيد الإجراءات، التفويض واختيار الخيارات. وفقًا لـ Apple HIG، 2025، يجب ألا تشغل العروض المشروطة أكثر من 20% من سيناريوهات التنقل في التطبيق. في Android، يتم تنفيذ المشروطية من خلال DialogFragment وBottomSheet وActivity مع علامات تشغيل محددة.
أهم النقاط
العرض المشروط هو نمط تنقل تظهر فيه شاشة جديدة فوق الشاشة الحالية، مما يمنع مؤقتًا التفاعل مع المحتوى الأصلي. يجب على المستخدم إكمال المهمة المشروطة بشكل صريح (إلغاء، حفظ، إغلاق) للعودة إلى الحالة السابقة.
تحل المشروطية مهمة معرفية: فهي تركز انتباه المستخدم على إجراء واحد دون تشتيت من باقي الواجهة. هذا مهم للغاية لنماذج التسجيل وحوارات التأكيد واختيار الملفات والتفويض عبر خدمات الطرف الثالث. توصي Human Interface Guidelines من Apple باستخدام المشروطية فقط للمهام التي تتطلب الإكمال قبل المتابعة.
على عكس النوافذ المشروطة على الويب، يمكن أن يكون العرض المشروط في التطبيقات المحمولة بملء الشاشة (يشغل الشاشة بأكملها) أو جزئيًا (Page Sheet، Bottom Sheet). يعتمد اختيار النوع على سياق المهمة واتفاقيات المنصة. تميل iOS إلى استخدام Page Sheet لمعظم السيناريوهات، تاركة Full Screen لمشغلات الفيديو ومحررات الصور.
Push Presentation (التنقل بالكومة) يضيف شاشة إلى كومة التنقل ويظهر تلقائيًا زر الرجوع. يمكن للمستخدم العودة إلى الشاشة السابقة في أي وقت. العرض المشروط، على العكس، يتطلب إكمالًا صريحًا: زر الرجوع إما غائب أو يغلق النافذة المشروطة بدلاً من العودة إلى الشاشة السابقة.
الاختلافات الرئيسية بين العرض المشروط والدفع: العرض المشروط يمنع التنقل للخلف دون فقدان البيانات، ويتطلب إجراءً للإغلاق (Save، Cancel، Done)، ويمثل عادةً مهمة منفصلة. Push Presentation يحافظ على التسلسل الهرمي للتنقل، ويضيف تلقائيًا زر الرجوع، ومناسب لعرض المحتوى بالتسلسل.
| الخاصية | العرض المشروط | Push Presentation |
|---|---|---|
| منع الرجوع | نعم، يتطلب إجراءً صريحًا | لا، زر الرجوع متاح دائمًا |
| الاستخدام النموذجي | نماذج، تفويض، اختيار | عرض تفصيلي، تنقل |
| الرسوم المتحركة | من أسفل إلى أعلى (iOS)، انزلاق (Android) | من اليمين إلى اليسار (iOS) |
| كومة التنقل | لا يضاف إلى الكومة الرئيسية | يضاف إلى الكومة |
من الناحية العملية، يعتمد الاختيار بين Modal وPush على السياق. يوصى باستخدام المشروطية للمهام التي يجب على المستخدم إكمالها قبل المتابعة، وPush للاستكشاف التسلسلي للمحتوى. يؤدي خلط الأنماط على نفس الشاشة إلى الارتباك ويضعف تجربة المستخدم.
iOS يقدم عدة أنماط للعرض المشروط من خلال تعداد UIModalPresentationStyle. يدعم UIKit .fullScreen (ملء الشاشة)، و.pageSheet (بطاقة بهامش علوي)، و.formSheet (نافذة مركزية على iPad)، و.automatic (يختار النظام بناءً على السياق). منذ iOS 13، أصبح النمط الافتراضي .automatic الذي يختار .pageSheet لـ iPhone.
الطريقة الأساسية في UIKit للعرض المشروط هي present(_:animated:completion:). يصبح المتحكم الذي يستدعي الطريقة هو presentingViewController، والجديد يصبح presentedViewController. يتم الإغلاق من خلال dismiss(animated:completion:). يوفر SwiftUI المعدّل .sheet لسلوك مماثل.
يستخدم النهج التصريحي لـ SwiftUI المعدّلات .sheet و .fullScreenCover. الأول ينشئ Page Sheet، والثاني ينشئ عرضًا مشروطًا بملء الشاشة. يقبل كلاهما ربطًا بقيمة Bool أو كائن قابل للتحديد يتحكم في رؤية النافذة المشروطة. يحدث الإغلاق عند تعيين الربط إلى false أو عند استدعاء dismiss من البيئة.
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. بدلاً من ذلك، تقدم المنصة عدة آليات: DialogFragment للنوافذ الحوارية، وBottomSheetDialogFragment للألواح السفلية، وActivity مع علامات NEW_TASK وCLEAR_TOP للشاشات المشروطة. قدم Jetpack Compose مكونًا موحدًا Dialog لجميع أنواع النوافذ المشروطة.
DialogFragment هو الفئة الأساسية للنوافذ المشروطة في Android SDK. يدير دورة حياة الحوار، ويعالج تدوير الشاشة، ويحفظ الحالة. يتم عرض الجزء فوق Activity دون حظر كومة التنقل. يتم الإغلاق من خلال dismiss() أو بالنقر خارج منطقة الحوار إذا كان setCancelable(true).
BottomSheetDialogFragment يعرض نافذة مشروطة كلوحة ترتفع من الأسفل. هذا النمط شائع في Material Design لاختيار الخيارات والمشاركة والإجراءات السريعة. يمكن أن يكون BottomSheet بارتفاع ثابت أو قابل للتوسيع (ارتفاع المعاينة + الارتفاع الكامل). في 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("إغلاق")
}
}
}
}
}
النوافذ المشروطة هي أداة قوية لتجربة المستخدم، لكن استخدامها المفرط يضعف تجربة المستخدم. تتفق Apple HIG وGoogle Material Design على التوصيات: يجب استخدام المشروطية للمهام المركزة وألا تتجاوز 20% من إجمالي إجراءات التنقل.
النوافذ المشروطة مناسبة للسيناريوهات: إدخال البيانات (نماذج التسجيل، الملفات الشخصية)، التأكيد (الحذف، الإرسال)، الاختيار (منتقي التاريخ، مدير الملفات)، التفويض (OAuth، Firebase Auth). إذا كانت المهمة تستغرق أقل من 30 ثانية وتتطلب حظر السياق، فاختر المشروطية.
لا تستخدم العرض المشروط لـ: عرض المحتوى بالتسلسل (استخدم Push)، عرض الأخطاء (استخدم Toast أو Snackbar)، الإعلانات والعروض الترويجية دون طلب صريح من المستخدم. Material Design يوصي بتجنب النوافذ المشروطة المتداخلة، فهذا يربك المستخدم ويعطل التسلسل الهرمي للتنقل.
بالنسبة للنوافذ المشروطة التي تحتوي على حقول نصية، تأكد من معالجة فقدان التركيز من لوحة المفاتيح. عند ظهور لوحة المفاتيح، يجب أن تتحرك النافذة المشروطة لأعلى حتى يرى المستخدم النص الذي يدخله. UIKeyboardWillShowNotification في iOS و adjustResize في Android تحل هذه المهمة.
دعنا نلقي نظرة على تنفيذ العرض المشروط على كلتا المنصتين. يوضح مثال Swift تكوين UIModalPresentationStyle.pageSheet مع مفوض لمعالجة الإغلاق. يوضح مثال Kotlin DialogFragment مع تخطيط مخصص وحفظ الحالة.
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()
}
}
}
الأسئلة الشائعة
استخدم العرض المشروط للمهام المركزة التي يجب على المستخدم إكمالها قبل المتابعة: النماذج والتأكيدات والتفويض. Push مناسب لعرض المحتوى بالتسلسل حيث يمكن للمستخدم التنقل بحرية للخلف. يجب ألا تحتوي النافذة المشروطة على تنقل داخلها.
منذ iOS 13، النمط الافتراضي .automatic يختار .pageSheet لـ iPhone. .pageSheet مناسب لمعظم السيناريوهات (النماذج، التفاصيل). .fullScreen للمحتوى الوسائطي (الفيديو، محررات الصور). .formSheet لتطبيقات iPad التي تحتاج نافذة مركزية.
Jetpack Compose يوفر مكون Dialog للنوافذ المشروطة البسيطة وModalBottomSheet للألواح السفلية. يقبل Dialog معامل onDismissRequest والمحتوى بنمط Compose. استخدم rememberSaveable داخل الحوار للحفاظ على الحالة.
Apple HIG و Material Design لا يوصيان بالنوافذ المشروطة المتداخلة. إذا فتح المستخدم نافذة مشروطة فوق نافذة مشروطة أخرى، يفقد السياق وقد يرتبك في التسلسل الهرمي. بدلاً من التداخل، استخدم مؤشر الخطوات أو نمط المعالج بنافذة مشروطة واحدة.
استخدم UIAdaptivePresentationControllerDelegate في iOS (طريقة presentationControllerShouldDismiss) أو OnBackPressedDispatcher في Android. عند وجود تغييرات غير محفوظة، اعرض AlertDialog مع خيارات: حفظ، تجاهل التغييرات، أو البقاء في الشاشة. هذا يمنع فقدان البيانات العرضي من قبل المستخدم.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا