إنشاء تنقُّل تكيُّفي

تحتوي معظم التطبيقات على بضعة وجهات من المستوى الأعلى يمكن الوصول إليها من خلال واجهة مستخدم التنقّل الأساسية في التطبيق. في النوافذ المدمجة، مثل شاشة هاتف قياسية، يتم عادةً عرض الوجهات في شريط تنقّل في قاع النافذة. في النافذة الموسّعة، مثل تطبيق معروض على الشاشة الكاملة على جهاز لوحي، يكون شريط التنقّل بجانب التطبيق عادةً خيارًا أفضل لأنّه يسهل الوصول إلى عناصر التحكّم في التنقّل أثناء تثبيت الجهاز باليد اليمنى واليسرى.

تعمل NavigationSuiteScaffold على تبسيط عملية التبديل بين واجهات مستخدم التنقّل من خلال عرض واجهة مستخدم التنقّل المناسبة التي يمكن إنشاؤها استنادًا إلى WindowSizeClass. ويشمل ذلك تغيير واجهة المستخدم ديناميكيًا أثناء تغييرات حجم النافذة في وقت التشغيل. يكون السلوك التلقائي هو عرض أيّ من مكوّنات واجهة المستخدم التالية:

  • شريط التنقّل إذا كان العرض أو الارتفاع مدمجَين أو إذا كان الجهاز في وضع على سطح مستوٍ
  • شريط التنقّل لكل العناصر الأخرى
الشكل 1. NavigationSuiteScaffold يعرض شريط تنقّل في النوافذ المصغّرة.
الشكل 2. NavigationSuiteScaffold يعرض شريط تنقّل في النوافذ الموسّعة.

إضافة التبعيات

NavigationSuiteScaffold هو جزء من مكتبة مجموعة التنقّل التكيُّفي في Material3. أضِف ملفًا ملحقًا للمكتبة في ملف build.gradle لتطبيقك أو وحدتك:

Kotlin

implementation("androidx.compose.material3:material3-adaptive-navigation-suite")

رائع

implementation 'androidx.compose.material3:material3-adaptive-navigation-suite'

إنشاء إطار عمل

الجزءان الرئيسيان من NavigationSuiteScaffold هما عناصر مجموعة التنقّل ومحتوى الوجهة المحدّدة. يمكنك تحديد عناصر مجموعة التنقّل مباشرةً في عنصر قابل للتجميع، ولكن من الشائع تحديد هذه العناصر في مكان آخر، على سبيل المثال، في قائمة أرقام مميزة:

enum class AppDestinations(
    @StringRes val label: Int,
    val icon: ImageVector,
    @StringRes val contentDescription: Int
) {
    HOME(R.string.home, Icons.Default.Home, R.string.home),
    FAVORITES(R.string.favorites, Icons.Default.Favorite, R.string.favorites),
    SHOPPING(R.string.shopping, Icons.Default.ShoppingCart, R.string.shopping),
    PROFILE(R.string.profile, Icons.Default.AccountBox, R.string.profile),
}

لاستخدام NavigationSuiteScaffold، عليك تتبُّع الوجهة الحالية، وهو ما يمكنك تنفيذه باستخدام rememberSaveable:

var currentDestination by rememberSaveable { mutableStateOf(AppDestinations.HOME) }

في المثال التالي، تستخدِم المَعلمة navigationSuiteItems (type NavigationSuiteScope) الدالة item لتحديد واجهة مستخدِم التنقّل لوجهة فردية. يتم استخدام واجهة مستخدم الوجهة في أشرطة التنقّل والحوامل والأدراج. لإنشاء عناصر التنقّل، عليك الانتقال إلى AppDestinations (المحدّد في المقتطف السابق):

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it }
            )
        }
    }
) {
    // TODO: Destination content.
}

ضمن دالة lambda لمحتوى الوجهة، استخدِم القيمة currentDestination لتحديد واجهة المستخدم التي سيتم عرضها. إذا كنت تستخدم مكتبة تنقّل في تطبيقك، استخدِمها هنا لعرض الوجهة المناسبة. يمكن أن تكون عبارة when كافية في الحالات التالية:

NavigationSuiteScaffold(
    navigationSuiteItems = { /*...*/ }
) {
    // Destination content.
    when (currentDestination) {
        AppDestinations.HOME -> HomeDestination()
        AppDestinations.FAVORITES -> FavoritesDestination()
        AppDestinations.SHOPPING -> ShoppingDestination()
        AppDestinations.PROFILE -> ProfileDestination()
    }
}

تغيير الألوان

NavigationSuiteScaffold ينشئ Surface على المنطقة بالكامل التي يشغلها السقالة، عادةً النافذة الكاملة. بالإضافة إلى ذلك، يرسم الهيكل الداعم واجهة مستخدم التنقل المحدّدة، مثل NavigationBar. يستخدم كلّ من واجهة مستخدِم السطح وواجهة مستخدِم التنقّل القيم المحدّدة في مظهر تطبيقك، ولكن يمكنك إلغاء قيم المظهر.

تحدّد المَعلمة containerColor لون السطح. الإعداد التلقائي هو لون خلفية نظام الألوان. تحدّد المَعلمة contentColor لون المحتوى على هذه المساحة. القيمة التلقائية هي لون "تفعيل" لأيّ عنصر تم تحديده لـ containerColor. على سبيل المثال، إذا كان containerColor يستخدم اللون background، سيستخدم contentColor اللون onBackground. اطّلِع على استخدام مظاهر أسلوب Material Design 3 في تطبيق "الإنشاء" لمزيد من التفاصيل حول آلية عمل نظام الألوان. عند إلغاء هذه القيم، استخدِم القيم المحدّدة في المظهر ليتيح تطبيقك وضعَي شاشة ملفتة وملفتة للنظر:

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    containerColor = MaterialTheme.colorScheme.primary,
    contentColor = MaterialTheme.colorScheme.onPrimary,
) {
    // Content...
}

يتم رسم واجهة مستخدم التنقّل أمام سطح NavigationSuiteScaffold. يتم توفير القيم التلقائية للألوان في واجهة المستخدم من قِبل NavigationSuiteDefaults.colors()، ولكن بإمكانك إلغاء هذه القيم أيضًا. على سبيل المثال، إذا كنت تريد أن تكون خلفية شريط التنقّل شفافة ولكن القيم الأخرى هي التلقائية، يمكنك إلغاء navigationBarContainerColor:

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    navigationSuiteColors = NavigationSuiteDefaults.colors(
        navigationBarContainerColor = Color.Transparent,
    )
) {
    // Content...
}

في النهاية، يمكنك تخصيص كل عنصر في واجهة مستخدم التنقّل. عند استدعاء الدالة item، يمكنك تمرير مثيل من NavigationSuiteItemColors. تحدِّد الفئة ألوان العناصر في شريط التنقّل وشريط التنقّل وصندوق التمرير للتنقّل. وهذا يعني أنّه يمكنك استخدام ألوان متطابقة في كل نوع من أنواع واجهة مستخدم التنقّل، أو يمكنك تغيير الألوان حسب احتياجاتك. حدِّد الألوان على مستوى NavigationSuiteScaffold لاستخدام مثيل العنصر نفسه لجميع العناصر واستخدِم الدالة NavigationSuiteDefaults.itemColors() لإلغاء الألوان التي تريد تغييرها فقط:

val myNavigationSuiteItemColors = NavigationSuiteDefaults.itemColors(
    navigationBarItemColors = NavigationBarItemDefaults.colors(
        indicatorColor = MaterialTheme.colorScheme.primaryContainer,
        selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer
    ),
)

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it },
                colors = myNavigationSuiteItemColors,
            )
        }
    },
) {
    // Content...
}

تخصيص أنواع التنقّل

يغيّر السلوك التلقائي للعنصر NavigationSuiteScaffold واجهة مستخدم التنقّل استنادًا إلى فئات حجم النافذة. ومع ذلك، قد تحتاج إلى إلغاء هذا السلوك. على سبيل المثال، إذا كان تطبيقك يعرض لوحة واحدة كبيرة للمحتوى في الخلاصة، يمكن للتطبيق استخدام ملف شخصي دائم للتنقل في النوافذ الموسّعة، مع الاستمرار في استخدام السلوك التلقائي لفئتي حجم النافذة الصغيرة والمتوسطة:

val adaptiveInfo = currentWindowAdaptiveInfo()
val customNavSuiteType = with(adaptiveInfo) {
    if (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) {
        NavigationSuiteType.NavigationDrawer
    } else {
        NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
    }
}

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    layoutType = customNavSuiteType,
) {
    // Content...
}

مصادر إضافية