يقدّم مكوّن التنقّل دعمًا لتطبيقات Jetpack Compose. يمكنك التنقّل بين العناصر القابلة للتجميع مع الاستفادة من البنية الأساسية والميزات في عنصر التنقّل.
ضبط إعدادات الجهاز
لتوفير ميزة Compose، استخدِم التبعية التالية في ملف build.gradle
الخاص بوحدة تطبيقك:
dependencies { def nav_version = "2.8.8" implementation "androidx.navigation:navigation-compose:$nav_version" }
dependencies { val nav_version = "2.8.8" implementation("androidx.navigation:navigation-compose:$nav_version") }
البدء
عند تنفيذ ميزة التنقّل في تطبيق، عليك تنفيذ مضيف تنقّل ورسم بياني و عنصر تحكّم. لمزيد من المعلومات، يُرجى الاطّلاع على النظرة العامة حول التنقّل.
إنشاء NavController
للحصول على معلومات حول كيفية إنشاء NavController
في Compose، راجِع قسم "إنشاء" في إنشاء وحدة تحكّم في التنقّل.
إنشاء NavHost
للحصول على معلومات عن كيفية إنشاء NavHost
في ميزة "الإنشاء"، يُرجى الاطّلاع على قسم "الإنشاء"
في مقالة تصميم الرسم البياني للتنقّل.
الانتقال إلى عنصر قابل للإنشاء
للحصول على معلومات عن الانتقال إلى عنصر Composable، يُرجى الاطّلاع على الانتقال إلى وجهة في مستندات التصميم.
التنقّل باستخدام الوسيطات
للحصول على معلومات حول تمرير الوسيطات بين الوجهات القابلة للإنشاء، راجِع القسم "إنشاء" في تصميم الرسم البياني للتنقّل.
استرداد البيانات المعقدة عند التنقل
ننصح بشدة بعدم تمرير عناصر بيانات معقّدة عند التنقّل، وبدلاً من ذلك، تمرير الحد الأدنى من المعلومات اللازمة، مثل معرّف فريد أو شكل آخر من أشكال المعرّفات، كوسيطات عند تنفيذ إجراءات التنقّل:
// Pass only the user ID when navigating to a new destination as argument
navController.navigate(Profile(id = "user1234"))
يجب تخزين العناصر المعقدة كبيانات في مصدر واحد للحقيقة، مثل
طبقة البيانات. بعد الوصول إلى وجهتك بعد التنقّل، يمكنك تحميل المعلومات المطلوبة من مصدر واحد باستخدام رقم التعريف الذي تم تمريره. لاسترداد الوسيطات في ViewModel
المسؤولة عن
الوصول إلى طبقة البيانات، استخدِم SavedStateHandle
ViewModel
:
class UserViewModel(
savedStateHandle: SavedStateHandle,
private val userInfoRepository: UserInfoRepository
) : ViewModel() {
private val profile = savedStateHandle.toRoute<Profile>()
// Fetch the relevant user information from the data layer,
// ie. userInfoRepository, based on the passed userId argument
private val userInfo: Flow<UserInfo> = userInfoRepository.getUserInfo(profile.id)
// …
}
يساعد هذا الأسلوب على منع فقدان البيانات أثناء تغييرات التهيئة وأي تناقضات عند تحديث الكائن المعني أو تغييره.
للحصول على شرح أكثر تفصيلاً حول سبب تجنُّب تمرير البيانات المعقدة كصعوبات، بالإضافة إلى قائمة بأنواع الصعوبات المتوافقة، اطّلِع على مقالة تمرير البيانات بين الوجهات.
روابط لصفحات معيّنة
تدعم ميزة "إنشاء التنقل" الروابط لمواضع معيّنة التي يمكن تحديدها كجزء من وظيفة composable()
أيضًا. تقبل المَعلمة deepLinks
قائمة بعناصر
NavDeepLink
التي يمكن إنشاؤها بسرعة باستخدام الطريقة
navDeepLink()
:
@Serializable data class Profile(val id: String)
val uri = "https://www.example.com"
composable<Profile>(
deepLinks = listOf(
navDeepLink<Profile>(basePath = "$uri/profile")
)
) { backStackEntry ->
ProfileScreen(id = backStackEntry.toRoute<Profile>().id)
}
تتيح لك هذه الروابط لصفحات معيّنة ربط عنوان URL أو إجراء أو نوع MIME مع ملف
قابل للتركيب. ولا تكون هذه الروابط لصفحات في التطبيق متاحة للتطبيقات الخارجية تلقائيًا. لجعل هذه الروابط لصفحات في التطبيق متاحة خارجيًا، يجب إضافة عناصر
<intent-filter>
المناسبة إلى ملف manifest.xml
في تطبيقك. لتفعيل الرابط المؤدي إلى صفحة معيّنة في المثال السابق، عليك إضافة ما يلي داخل عنصر
<activity>
في البيان:
<activity …>
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
</intent-filter>
</activity>
تؤدي عملية التنقّل تلقائيًا إلى إنشاء رابط لصفحة في التطبيق عندما يشغّل تطبيق آخر الرابط لصفحة في التطبيق.
يمكن أيضًا استخدام هذه الروابط لصفحات في التطبيق نفسها لإنشاء PendingIntent
باستخدام الرابط المؤدي لصفحة معيّنة مناسبة من عنصر قابل للإنشاء:
val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"https://www.example.com/profile/$id".toUri(),
context,
MyActivity::class.java
)
val deepLinkPendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
يمكنك بعد ذلك استخدام هذا deepLinkPendingIntent
مثل أي PendingIntent
آخر ل
فتح تطبيقك في وجهة الرابط لصفحة في التطبيق.
التنقّل المتداخل
للحصول على معلومات حول كيفية إنشاء رسوم بيانية متداخلة للتنقّل، يُرجى الاطّلاع على الرسومات البيانية المضمَّنة.
الدمج مع شريط التنقّل السفلي
من خلال تحديد NavController
على مستوى أعلى في التسلسل الهرمي القابل للتجميع،
يمكنك ربط Navigation بمكونات أخرى، مثل مكونات التنقل في أسفل الشاشة. يتيح لك القيام بذلك التنقل عن طريق تحديد
الأيقونات في الشريط السفلي.
لاستخدام مكوّنات BottomNavigation
وBottomNavigationItem
،
أضِف التبعية androidx.compose.material
إلى تطبيق Android.
dependencies { implementation "androidx.compose.material:material:1.7.5" } android { buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion = "1.5.15" } kotlinOptions { jvmTarget = "1.8" } }
dependencies { implementation("androidx.compose.material:material:1.7.5") } android { buildFeatures { compose = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.15" } kotlinOptions { jvmTarget = "1.8" } }
لربط العناصر في شريط التنقّل السفلي بالمسارات في الرسم البياني للتنقّل،
ننصح بتحديد فئة، مثل TopLevelRoute
المعروضة هنا، التي تحتوي على
فئة مسار ورمز.
data class TopLevelRoute<T : Any>(val name: String, val route: T, val icon: ImageVector)
بعد ذلك، ضَع هذه المسارات في قائمة يمكن استخدامها من قِبل
BottomNavigationItem
:
val topLevelRoutes = listOf(
TopLevelRoute("Profile", Profile, Icons.Profile),
TopLevelRoute("Friends", Friends, Icons.Friends)
)
في BottomNavigation
القابلة للإنشاء، احصل على NavBackStackEntry
الحالي
باستخدام الدالة currentBackStackEntryAsState()
. يمنحك هذا الإدخال إذن الوصول
إلى NavDestination
الحالي. يمكن بعد ذلك تحديد الحالة المحدّدة لكل
BottomNavigationItem
من خلال مقارنة مسار العنصر بمسار الوجهة الحالية ووجهاتها الرئيسية للتعامل مع الحالات
عند استخدام التنقل المدمج باستخدام التدرّج الهرمي NavDestination
.
يتم أيضًا استخدام مسار العنصر لربط onClick
lambda باستدعاء
navigate
بحيث يؤدي النقر على العنصر إلى الانتقال إلى ذلك العنصر. باستخدام علامتَي
saveState
وrestoreState
، يتم حفظ الحالة والمكدس الخلفي لهذا العنصر
بشكل صحيح واستعادتهما عند التبديل بين عناصر شريط التنقّل في أسفل الشاشة.
val navController = rememberNavController()
Scaffold(
bottomBar = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
topLevelRoutes.forEach { topLevelRoute ->
BottomNavigationItem(
icon = { Icon(topLevelRoute.icon, contentDescription = topLevelRoute.name) },
label = { Text(topLevelRoute.name) },
selected = currentDestination?.hierarchy?.any { it.hasRoute(topLevelRoute.route::class) } == true,
onClick = {
navController.navigate(topLevelRoute.route) {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the back stack as users select items
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true
}
}
)
}
}
}
) { innerPadding ->
NavHost(navController, startDestination = Profile, Modifier.padding(innerPadding)) {
composable<Profile> { ProfileScreen(...) }
composable<Friends> { FriendsScreen(...) }
}
}
وهنا يمكنك الاستفادة من طريقة NavController.currentBackStackEntryAsState()
لرفع الحالة navController
من الدالة NavHost
ومشاركتها مع المكوِّن BottomNavigation
. وهذا يعني أنّه
BottomNavigation
تتضمن تلقائيًا أحدث حالة.
إمكانية التشغيل التفاعلي
إذا كنت تريد استخدام مكوِّن التنقل مع ميزة Compose، فلديك خياران:
- حدِّد رسمًا بيانيًا للتنقّل باستخدام مكوّن التنقّل للمقاطع.
- حدّد رسمًا بيانيًا للتنقل مع
NavHost
في Compose باستخدام وجهات Compose. لا يمكن ذلك إلا إذا كانت جميع الشاشات في الرسم البياني للتنقل قابلة للإنشاء.
لذلك، ننصحك باستخدام المكوّن التنقّل المستنِد إلى المقتطفات في التطبيقات المختلطة التي تتضمّن ميزتَي "إنشاء" و"عرض". ستحتوي الأجزاء بعد ذلك على شاشات مستندة إلى "العرض" وشاشات "الإنشاء" والشاشات التي تستخدم كلّ من "العرض" و"الإنشاء". بعد أن تصبح محتويات كل قطعة في "أداة الإنشاء"، تكون الخطوة التالية هي ربط كل هذه الشاشات معًا باستخدام "أداة التنقّل" وإزالة كل القطع.
التنقّل من ميزة "الإنشاء" باستخدام ميزة "التنقّل" للأجزاء
لتغيير الوجهات داخل رمز الإنشاء، عليك عرض الأحداث التي يمكن تمريرها إلى أيّ عنصر قابل للتركيب في التسلسل الهرمي وتشغيله:
@Composable
fun MyScreen(onNavigate: (Int) -> Unit) {
Button(onClick = { onNavigate(R.id.nav_profile) } { /* ... */ }
}
في المقتطف، يمكنك إنشاء رابط بين Compose ومكوّن التنقّل المستنِد إلى المقتطف من خلال العثور على NavController
والانتقال إلى الوجهة:
override fun onCreateView( /* ... */ ) {
setContent {
MyScreen(onNavigate = { dest -> findNavController().navigate(dest) })
}
}
بدلاً من ذلك، يمكنك تمرير NavController
لأسفل التسلسل الهرمي "إنشاء".
ومع ذلك، فإنّ عرض الدوال البسيطة يمكن إعادة استخدامها واختبارها بشكلٍ أكبر.
الاختبار
عليك فصل رمز التنقّل عن الوجهات القابلة للتجميع لتتمكّن من اختبار
كل عنصر قابل للتجميع بشكل منفصل، بمعزل عن العنصر القابل للتجميع NavHost
.
وهذا يعني أنّه يجب عدم تمرير navController
مباشرةً إلى أي عنصر
قابل للتجميع، بل يجب تمرير طلبات استدعاء التنقّل كمَعلمات. يتيح ذلك اختبار
جميع العناصر القابلة للتجميع بشكلٍ فردي، لأنّها لا تتطلّب
مثيلًا من navController
في الاختبارات.
إنّ مستوى التوجيه غير المباشر الذي يوفّره composable
lambda هو ما يتيح لك
فصل رمز التنقّل عن العنصر القابل للتجميع نفسه. ويعمل ذلك في اتجاهين:
- لا تُمرِّر سوى الوسائط التي تم تحليلها إلى العنصر القابل للتجميع.
- نقْل الدوالّ التي يجب أن يبدأها العنصر القابل للتجميع للتنقّل، بدلاً من
NavController
نفسه
على سبيل المثال، قد يتضمّن العنصر القابل للتجميع ProfileScreen
الذي يأخذ userId
كمدخل ويسمح للمستخدمين بالانتقال إلى صفحة الملف الشخصي لصديق التوقيع التالي:
@Composable
fun ProfileScreen(
userId: String,
navigateToFriendProfile: (friendUserId: String) -> Unit
) {
…
}
بهذه الطريقة، تعمل العناصر القابلة للتجميع في ProfileScreen
بشكل مستقل عن التنقّل،
ما يتيح اختبارها بشكل مستقل. ستُغلِّف دالة composable
lambda
الحد الأدنى من المنطق المطلوب لسد الفجوة بين واجهات برمجة التطبيقات
للتنقّل والعنصر القابل للتجميع:
@Serializable data class Profile(id: String)
composable<Profile> { backStackEntry ->
val profile = backStackEntry.toRoute<Profile>()
ProfileScreen(userId = profile.id) { friendUserId ->
navController.navigate(route = Profile(id = friendUserId))
}
}
نقترح عليك كتابة اختبارات تغطي متطلبات التنقّل في التطبيق من خلال اختبار NavHost
وإجراءات التنقّل التي يتم تمريرها إلى العناصر القابلة للإنشاء بالإضافة إلى العناصر الفردية القابلة للإنشاء.
اختبار NavHost
لبدء اختبار NavHost
، أضِف التبعية التالية لاختبار التنقّل:
dependencies {
// ...
androidTestImplementation "androidx.navigation:navigation-testing:$navigationVersion"
// ...
}
احرِص على تضمين NavHost
في تطبيقك ضمن عنصر قابل للتجميع يقبل NavHostController
كمَعلمة.
@Composable
fun AppNavHost(navController: NavHostController){
NavHost(navController = navController){ ... }
}
يمكنك الآن اختبار AppNavHost
وكل منطق التنقّل المحدّد داخل
NavHost
من خلال تمرير مثيل لعنصر اختبار التنقّل
TestNavHostController
. سيظهر اختبار واجهة المستخدم الذي يتحقق من وجهة البدء ل
تطبيقك وNavHost
على النحو التالي:
class NavigationTest {
@get:Rule
val composeTestRule = createComposeRule()
lateinit var navController: TestNavHostController
@Before
fun setupAppNavHost() {
composeTestRule.setContent {
navController = TestNavHostController(LocalContext.current)
navController.navigatorProvider.addNavigator(ComposeNavigator())
AppNavHost(navController = navController)
}
}
// Unit test
@Test
fun appNavHost_verifyStartDestination() {
composeTestRule
.onNodeWithContentDescription("Start Screen")
.assertIsDisplayed()
}
}
اختبار إجراءات التنقّل
يمكنك اختبار تنفيذ التنقّل بطرق متعدّدة، من خلال تنفيذ نقرات على عناصر واجهة المستخدم، ثم التحقّق من الوجهة المعروضة أو مقارنة المسار المتوقّع بالمسار الحالي.
بما أنّك تريد اختبار تنفيذ تطبيقك المحدّد، يُفضَّل استخدام النقرات على واجهة المستخدم. للتعرّف على كيفية اختبار ذلك إلى جانب الدوالّ القابلة للتجميع الفردية بشكل منفصل، احرص على الاطّلاع على الاختبار في Jetpack Compose codelab.
يمكنك أيضًا استخدام navController
للتحقق من تأكيداتك من خلال مقارنة
المسار الحالي بالطريق المتوقّع، باستخدام currentBackStackEntry
في navController
:
@Test
fun appNavHost_clickAllProfiles_navigateToProfiles() {
composeTestRule.onNodeWithContentDescription("All Profiles")
.performScrollTo()
.performClick()
assertTrue(navController.currentBackStackEntry?.destination?.hasRoute<Profile>() ?: false)
}
للحصول على مزيد من الإرشادات حول أساسيات اختبار Compose، يمكنك الاطّلاع على اختبار تنسيق Compose والاختبار في Jetpack Compose في ورشة التعلم. للاطّلاع على مزيد من المعلومات عن الاختبار المتقدّم لرمز التنقّل، يُرجى الانتقال إلى دليل اختبار التنقّل.
مزيد من المعلومات
للاطّلاع على مزيد من المعلومات عن Jetpack Navigation، اطّلِع على مقالة البدء في استخدام ملف Navigation البرمجي أو اطّلِع على الدليل التعليمي حول ملف التنقّل في Jetpack Compose.
للتعرّف على كيفية تصميم تنقّل تطبيقك ليتلاءم مع أحجام الشاشة واتجاهاتها وأشكالها المختلفة، اطّلِع على مقالة التنقّل في واجهات المستخدم السريعة الاستجابة.
للتعرّف على طريقة أكثر تقدمًا لتنفيذ تنقّل Compose في تطبيق مُقسَّم إلى وحدات، بما في ذلك مفاهيم مثل الرسوم البيانية المتداخلة ودمج شريط التنقّل في أسفل الشاشة، يمكنك الاطّلاع على تطبيق Now in Android على GitHub.
نماذج
تتيح Microsoft للمستخدمين والمؤسسات العمل والتعلّم والتنظيم والتواصل والابتكار من خلال تطبيقاتهم الرائدة في Microsoft 365. ولتحقيق ذلك، تدرك الشركة أنّه من الضروري توفير تجربة إنتاجية مثالية لعملائها على جميع الأجهزة التي يستخدمونها. تساعد منصّة Square ملايين البائعين في إدارة
نشاطك التجاري، بدءًا من المعالجة الآمنة لبطاقات الائتمان ووصولاً إلى حلول نقاط البيع
إعداد متجر مجاني على الإنترنت. تم نقل المربع إلى واجهة المستخدم التعريفية
لفترة من الوقت ولكن بدلاً من الاستمرار في بناء Monzo هو مصرف وتطبيق يقدّمان
الخدمات المالية الرقمية. مهمتهم هي تحقيق الأرباح
للجميع. بدأ نظام تصميم مونزو ينحرف عن Material Design بحيث
أرادوا طريقة سهلة لكتابة المكوّنات المخصصة وصيانتها تتطوّر باستمرار، لذا اختارت Jetpack Compose. باستخدام منصة Twitter هي واحدة من أكثر وسائل التواصل الاجتماعي استخدامًا
ومنصات الوسائط التي تتيح للمستخدمين رؤية ما يحدث في العالم في أي وقت
اللحظة. بدأ الفريق الهندسي باستخدام Jetpack Compose لتجديد
نظام التصميم. بما أنّه تم تطوير مكونات واجهة المستخدم شركة Cuvva تحسّن التأمين بشكل كبير
من خلال منحك طريقة مرنة حقًا لإدارة الغلاف، كل ذلك من خلال هاتفك.
كان على مهندسي Android في Cuvva قضاء بعض الوقت في إعادة هندسة تطبيقاتهم
وقررت اعتماد تدفق بيانات أحادي الاتجاه وJetpack Compose. بهذه الطريقة
يمكنهم ShareChat is a leading social media platform in India that allows users to share their opinions, document their lives, and make new friends in their native language. The standard Red Up Green Down color scheme that many wealth management app users take for granted can be very problematic for colorblind users and those with color vision deficiency.The Futubull team is embracing users’ needs by making concrete improvements so that everyone can grasp the key to wealth. TikTok, the world’s community-driven entertainment destination, brings over 1 billion people together from around the world to discover, create and share content they love. OkCredit is a credit account management app for millions of shop owners and their customers in India. With 140M transactions month over month, and 50M+ downloads, last year alone saw OkCredit recording $50 billion worth of transactions on the app. Operating at such a huge scale scale, OkCredit created a smooth and seamless experience for all their users by focusing on reducing ANRs and improving the app startup time. Lyft is committed to app excellence. They have to be. For a rideshare app — providing a vital, time-sensitive service to millions of drivers and riders every day — a slow or unresponsive app adds unacceptable friction. Josh is a short-video app from India, launched in 2020. One of the fastest growing short-video apps with over 124 million MAUs, optimizing it across a range of devices (high, mid, low end) and maintaining a standard experience across all of them is critical for their success. Improving app startups time and making the app responsive helped them achieve success. Microsoft Lens increases developer productivity using CameraX Zomato is an Indian multinational restaurant aggregator and food delivery company serving customers across 500 cities in India alone. In order to launch new features on their Android app, Headspace spent 8 months refactoring their architecture and rewriting in Kotlin. Learn how this reboot helped their business grow. Google Photos is the home for your memories, and their development team believes people should be able to enjoy those memories across all devices. Learn how Duolingo made the business decision to focus on Android performance and how they improved developer productivity and scaled their business. Mercari allows millions of people to shop and sell almost anything. The company was founded in 2013 in Japan, and it now is the largest smartphone-focused C2C marketplace in Japan. Google Duo is a simple, high quality video calling app for everyone. With the increase of people being at home during the Covid-19 pandemic, the Duo team saw a significant increase in people using the app to stay connected with friends & family, school and work. Headspace drive business growth by investing in Android app quality. SmartNews helps millions of people discover their world everyday by sharing timely news from a diverse set of news sources. Twitter is one of the most widely used social media platforms where users can see what’s happening in the world at any given moment. Delight Room Alarmy is an alarm app that can be turned off only when the pre-selected activities, such as taking a photo, solving a math problem, shaking phone, etc., are performed by the user. The Google Home app helps set up, manage, and control your Google Home, Google Nest, and Chromecast devices—plus thousands of connected home products like lights, cameras, thermostats, and more. Truecaller is an app that offers caller identification, call blocking, chat messaging and organized inbox. The app has a basic offering and a premium version which is ad-free and has a variety of unlocked features like advanced spam blocking and call recording.تمكّنت Microsoft Outlook وTeams وOffice من زيادة عدد المستخدمين النشطين والاحتفاظ بالمستخدمين باستخدام الشاشات الكبيرة.
يحقّق المربع زيادة في الإنتاجية باستخدام Compose
تنشئ Monzo تطبيقًا أكثر فعالية وجودة باستخدام Compose
شركة Twitter تحقّق زيادة في كفاءة وسرعة المطوّرين باستخدام Compose
تنشئ شركة Cuvva أكثر سرعة وبجودة أعلى من خلال Compose.
ShareChat addresses Jank issues to increase feed scrolling by 60%
The Key to Wealth for Everyone
TikTok Optimizes User Experience with Android Tools
OkCredit’s average merchant transaction goes up by 30% after reducing ANR
Lyft improves Android app startup time for drivers by 21%
Josh sees increased customer retention by improving app startup time by 30%
Microsoft Lens increases developer productivity using CameraX
Increasing app speed by 30%: a key ingredient in Zomato’s growth recipe
Headspace's Android reboot increases monthly active users by 15%
Google Photos increased daily active users by building for large screens
Duolingo refactors on Android with MVVM and Jetpack libraries
Mercari improves UI development productivity by 56% with Jetpack Compose
Google Duo sees increased engagement and improved ratings by optimizing for larger screens
Headspace drive business growth by investing in Android app quality
SmartNews reduces lines of code by 20% and improves team morale with Kotlin
Twitter increases developer productivity and code reliability with Kotlin
Delight Room increased 90% of its organic US users with Play Console
Google Home reduces #1 cause of crashes by 33%
Truecaller brings ~40% subscribers back with real time developer notifications
ما من اقتراحات في الوقت الحالي.
يُرجى محاولة تسجيل الدخول إلى حسابك على Google.