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

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

تسهّل السمة 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. يمكنك الاطّلاع على مظاهر التصميم المتعدد الأبعاد 3 في Compose لمزيد من التفاصيل حول آلية عمل نظام الألوان. عند إلغاء هذه القيم، استخدِم القيم المحدّدة في المظهر لكي يتيح تطبيقك وضعي العرض الداكن والفاتح:

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.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND)) {
        NavigationSuiteType.NavigationDrawer
    } else {
        NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
    }
}

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

مراجع إضافية