يمكنك استخدام مكتباتك المفضّلة في Compose. يصف هذا القسم كيفية دمج عدد قليل من المكتبات الأكثر فائدة.
النشاط
لاستخدام Compose في نشاط، يجب استخدام
ComponentActivity،
وهي فئة فرعية من Activity توفّر LifecycleOwner المناسبة
والمكوّنات لـ Compose. وتوفّر أيضًا واجهات برمجة تطبيقات إضافية تفصل الرمز البرمجي
عن طرق الإلغاء في فئة النشاط.
تتيح واجهة برمجة التطبيقات Activity Compose
استخدام واجهات برمجة التطبيقات هذه في الدوال المركّبة، وبالتالي لن تحتاج إلى إلغاء الطرق خارج الدوال المركّبة أو استرداد مثيل Activity صريح.
بالإضافة إلى ذلك، تضمن واجهات برمجة التطبيقات هذه أنّه يتم إعدادها مرة واحدة فقط، وأنّها تظلّ متاحة بعد إعادة الإنشاء، وأنّه يتم تنظيفها بشكل صحيح إذا تمت إزالة الدالة المركّبة من التركيب.
نتيجة النشاط
تتيح لك واجهة برمجة التطبيقات
rememberLauncherForActivityResult()
الحصول على نتيجة من نشاط
في الدالة المركّبة:
@Composable fun GetContentExample() { var imageUri by remember { mutableStateOf<Uri?>(null) } val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> imageUri = uri } Column { Button(onClick = { launcher.launch("image/*") }) { Text(text = "Load Image") } Image( painter = rememberAsyncImagePainter(imageUri), contentDescription = "My Image" ) } }
يوضّح هذا المثال عقدًا بسيطًا من نوع
GetContent(). يؤدي النقر على الزر إلى إرسال الطلب. يتم استدعاء دالة lambda اللاحقة لـ
rememberLauncherForActivityResult()
بعد أن يختار المستخدم صورة ويعود إلى النشاط الذي بدأه.
يؤدي ذلك إلى تحميل الصورة المحدّدة باستخدام دالة rememberImagePainter()
في Coil.
يمكن استخدام أي فئة فرعية من
ActivityResultContract
كوسيطة أولى لـ
rememberLauncherForActivityResult().
هذا يعني أنه يمكنك استخدام هذه التقنية لطلب المحتوى من إطار العمل
وفي أنماط شائعة أخرى. يمكنك أيضًا إنشاء عقود مخصّصة خاصة بك واستخدامها مع هذه الطريقة.
طلب أذونات التشغيل
يمكن استخدام واجهة Activity Result API نفسها و
rememberLauncherForActivityResult()
الموضَّحة أعلاه
لطلب أذونات التشغيل
باستخدام عقد
RequestPermission
لإذن واحد أو عقد
RequestMultiplePermissions
لأذونات متعددة.
يمكن أيضًا استخدام مكتبة Accompanist Permissions كطبقة فوق واجهات برمجة التطبيقات هذه لربط الحالة الحالية الممنوحة للأذونات بالحالة التي يمكن لواجهة مستخدم Compose استخدامها.
التعامل مع زر الرجوع في النظام
لتوفير ميزة التنقّل للخلف المخصّصة
وتجاوز الإعداد التلقائي لزر الرجوع في النظام من داخل
الدالة المركّبة، يمكن للدالة المركّبة استخدام
BackHandler
لاعتراض هذا الحدث:
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
تتحكّم الوسيطة الأولى في ما إذا كان
BackHandler
مفعَّلاً حاليًا، ويمكنك استخدام هذه الوسيطة لإيقاف المعالِج مؤقتًا
استنادًا إلى حالة المكوّن. سيتم استدعاء دالة lambda اللاحقة إذا
بدأ المستخدم حدث رجوع في النظام، وكان
BackHandler
مفعَّلاً حاليًا.
ViewModel
إذا كنت تستخدم مكتبة Architecture Components
ViewModel، يمكنك الوصول إلى
ViewModel من أي دالة مركّبة من خلال
استدعاء الدالة
viewModel(). أضِف التبعية التالية إلى ملف Gradle:
أنيق
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0' }
Kotlin
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0") }
يمكنك بعد ذلك استخدام الدالة viewModel() في الرمز البرمجي.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
تعرض الدالة viewModel() عنصر ViewModel حاليًا أو تنشئ عنصرًا جديدًا. By default,
the returned ViewModel is scoped to the enclosing activity, fragment or
navigation destination, and is retained as long as the scope is alive.
على سبيل المثال، إذا تم استخدام الدالة المركّبة في نشاط معيّن، تعرض الدالة viewModel()
النسخة نفسها إلى أن ينتهي النشاط أو يتم إنهاء العملية.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( // Returns the same instance as long as the activity is alive, // just as if you grabbed the instance from an Activity or Fragment viewModel: MyViewModel = viewModel() ) { /* ... */ } @Composable fun MyScreen2( viewModel: MyViewModel = viewModel() // Same instance as in MyScreen ) { /* ... */ }
إرشادات الاستخدام
يمكنك عادةً الوصول إلى مثيلات ViewModel في الدوال المركّبة على مستوى الشاشة، أي بالقرب من دالة مركّبة جذرية يتم استدعاؤها من نشاط أو جزء أو وجهة في رسم بياني للتنقّل. ويعود السبب في ذلك إلى أنّ ViewModels
تكون تلقائيًا ضمن نطاق عناصر مستوى الشاشة هذه. يمكنك الاطّلاع على مزيد من المعلومات حول
دورة حياة ViewModel
ونطاقه هنا.
يُرجى تجنُّب تمرير مثيلات ViewModel إلى دوال مركّبة أخرى لأنّ ذلك قد يجعل اختبار هذه الدوال المركّبة أكثر صعوبة وقد يؤدي إلى تعطُّل المعاينات. بدلاً من ذلك، مرِّر فقط البيانات
والوظائف التي تحتاجها كمعلمات.
يمكنك استخدام مثيلات ViewModel
لإدارة الحالة للدوال المركّبة على مستوى الشاشة الفرعية، ولكن يجب الانتباه إلى
مراحل النشاط ونطاق
ViewModel. إذا كانت الدالة المركّبة قائمة بذاتها، يمكنك استخدام Hilt لإدخال ViewModel لتجنُّب تمرير التبعيات من الدوال المركّبة الرئيسية.
إذا كان ViewModel يتضمّن تبعيات، تأخذ السمة viewModel() مَعلمة اختيارية
ViewModelProvider.Factory.
لمزيد من المعلومات حول ViewModel في Compose وكيفية استخدام النُسخ
مع مكتبة Navigation Compose أو الأنشطة والأجزاء،
يُرجى الاطّلاع على مستندات إمكانية التشغيل التفاعلي.
مصادر البيانات
تتضمّن Compose إضافات لحلول البث الأكثر رواجًا في Android. يتم توفير كل من هذه الإضافات من خلال عنصر مختلف:
LiveData.observeAsState()مضمّنة في العنصرandroidx.compose.runtime:runtime-livedata:$composeVersion.- لا يتطلّب
Flow.collectAsState()أي تبعيات إضافية. Observable.subscribeAsState()مضمّن في العنصرandroidx.compose.runtime:runtime-rxjava2:$composeVersionأوandroidx.compose.runtime:runtime-rxjava3:$composeVersion.
يتم تسجيل هذه العناصر كمستمع وتمثّل القيم كـ State. عندما يتم إصدار قيمة جديدة،
يعيد Compose إنشاء أجزاء واجهة المستخدم التي يتم فيها استخدام state.value. على سبيل المثال، في هذا الرمز، تتم إعادة إنشاء ShowData في كل مرة
يُصدر فيها exampleLiveData قيمة جديدة.
// import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { val dataExample = viewModel.exampleLiveData.observeAsState() // Because the state is read here, // MyScreen recomposes whenever dataExample changes. dataExample.value?.let { ShowData(dataExample) } }
العمليات غير المتزامنة في Compose
يتيح لك Jetpack Compose تنفيذ عمليات غير متزامنة باستخدام الروتينات المشتركة من داخل الدوال المركّبة.
يمكنك الاطّلاع على واجهات برمجة التطبيقات LaunchedEffect وproduceState وrememberCoroutineScope في مستندات الآثار الجانبية لمزيد من المعلومات.
التنقل
يوفّر مكوّن التنقّل إمكانية استخدام تطبيقات Jetpack Compose. لمزيد من المعلومات، يُرجى الاطّلاع على التنقّل باستخدام Compose ونقل بيانات Jetpack Navigation إلى Navigation Compose.
Hilt
Hilt هو الحلّ المقترَح لإدخال التبعية في تطبيقات Android، وهو يعمل بسلاسة مع Compose.
تستخدم دالة viewModel() المذكورة في قسم ViewModel تلقائيًا ViewModel الذي تنشئه Hilt باستخدام التعليق التوضيحي @HiltViewModel. لقد قدّمنا مستندات تتضمّن معلومات حول دمج ViewModel في Hilt.
@HiltViewModel class MyViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, private val repository: ExampleRepository ) : ViewModel() { /* ... */ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { /* ... */ }
Hilt والتنقّل
تتكامل Hilt أيضًا مع مكتبة Navigation Compose. أضِف الاعتماديات الإضافية التالية إلى ملف Gradle:
أنيق
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.4.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.4.0") }
عند استخدام Navigation Compose، استخدِم دائمًا الدالة المركّبة hiltViewModel
للحصول على نسخة من ViewModel الذي يتضمّن التعليق التوضيحي @HiltViewModel.
يعمل هذا مع الأجزاء أو الأنشطة التي تم التعليق عليها باستخدام
@AndroidEntryPoint.
على سبيل المثال، إذا كانت السمة ExampleScreen وجهة في رسم بياني للتنقّل،
يمكنك استدعاء السمة hiltViewModel() للحصول على مثيل للسمة ExampleViewModel ضمن نطاق
الوجهة كما هو موضّح في مقتطف الرمز أدناه:
// import androidx.hilt.navigation.compose.hiltViewModel @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" NavHost(navController, startDestination = startRoute) { composable("example") { backStackEntry -> // Creates a ViewModel from the current BackStackEntry // Available in the androidx.hilt:hilt-navigation-compose artifact val viewModel = hiltViewModel<MyViewModel>() MyScreen(viewModel) } /* ... */ } }
إذا كنت بحاجة إلى استرداد مثيل ViewModel ضمن نطاق
مسارات التنقّل أو الرسم البياني
للتنقّل
بدلاً من ذلك، استخدِم الدالة المركّبة hiltViewModel ومرِّر
backStackEntry المقابل كمَعلمة:
// import androidx.hilt.navigation.compose.hiltViewModel // import androidx.navigation.compose.getBackStackEntry @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" val innerStartRoute = "exampleWithRoute" NavHost(navController, startDestination = startRoute) { navigation(startDestination = innerStartRoute, route = "Parent") { // ... composable("exampleWithRoute") { backStackEntry -> val parentEntry = remember(backStackEntry) { navController.getBackStackEntry("Parent") } val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry) ExampleWithRouteScreen(parentViewModel) } } } }
ترقيم الصفحات
تسهّل مكتبة
Paging
تحميل البيانات تدريجيًا، وهي متوافقة مع Compose.
تحتوي صفحة إصدار Paging على معلومات حول تبعية paging-compose الإضافية التي يجب إضافتها إلى المشروع وإصداره.
في ما يلي مثال على واجهات برمجة التطبيقات Compose في مكتبة Paging:
@Composable fun MyScreen(flow: Flow<PagingData<String>>) { val lazyPagingItems = flow.collectAsLazyPagingItems() LazyColumn { items( lazyPagingItems.itemCount, key = lazyPagingItems.itemKey { it } ) { index -> val item = lazyPagingItems[index] Text("Item is $item") } } }
يمكنك الاطّلاع على مستندات القوائم والشبكات لمزيد من المعلومات حول استخدام ميزة "تقسيم الصفحات" في Compose.
خرائط
يمكنك استخدام مكتبة Maps Compose لتوفير "خرائط Google" في تطبيقك. إليك مثال على الاستخدام:
@Composable fun MapsExample() { val singapore = LatLng(1.35, 103.87) val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(singapore, 10f) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { Marker( state = remember { MarkerState(position = singapore) }, title = "Singapore", snippet = "Marker in Singapore" ) } }
التطبيقات المقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما يكون JavaScript غير مفعَّل
- الآثار الجانبية في Compose
- الحالة وJetpack Compose
- حفظ حالة واجهة المستخدم في Compose