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

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

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.
}

ضمن دالة لامدا لمحتوى الوجهة، استخدِم قيمة 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...
}

مراجع إضافية