يمكنك تضمين بنية Android View الهرمية في واجهة مستخدم Compose. ويكون هذا الأسلوب مفيدًا بشكل خاص إذا كنت تريد استخدام عناصر واجهة مستخدم غير متاحة بعد في Compose، مثل AdView.
يتيح لك هذا الأسلوب أيضًا إعادة استخدام طرق العرض المخصّصة التي صمّمتها.
لتضمين عنصر عرض أو بنية هرمية، استخدِم الدالة البرمجية القابلة للإنشاء AndroidView
. يتم تمرير دالة lambda إلى AndroidView تعرض View. توفّر AndroidView أيضًا update
دالة ردّ اتصال يتم استدعاؤها عند توسيع طريقة العرض. تتم إعادة إنشاء AndroidView
كلما تغيّرت قيمة State التي تم قراءتها في الدالة التنفيذية. تتلقّى الدالة AndroidView، مثل العديد من الدوال البرمجية الأخرى القابلة للإنشاء المضمّنة، المَعلمة Modifier التي يمكن استخدامها، على سبيل المثال، لضبط موضعها في الدالة البرمجية القابلة للإنشاء الرئيسية.
@Composable fun CustomView() { var selectedItem by remember { mutableIntStateOf(0) } // Adds view to Compose AndroidView( modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree factory = { context -> // Creates view MyView(context).apply { // Sets up listeners for View -> Compose communication setOnClickListener { selectedItem = 1 } } }, update = { view -> // View's been inflated or state read in this block has been updated // Add logic here if necessary // As selectedItem is read here, AndroidView will recompose // whenever the state changes // Example of Compose -> View communication view.selectedItem = selectedItem } ) } @Composable fun ContentExample() { Column(Modifier.fillMaxSize()) { Text("Look at this CustomView!") CustomView() } }
AndroidView مع ربط طرق العرض
لتضمين تصميم XML، استخدِم واجهة برمجة التطبيقات
AndroidViewBinding
التي توفّرها مكتبة androidx.compose.ui:ui-viewbinding. لإجراء ذلك، يجب أن يفعّل مشروعك ربط العرض.
@Composable fun AndroidViewBindingExample() { AndroidViewBinding(ExampleLayoutBinding::inflate) { exampleView.setBackgroundColor(Color.GRAY) } }
AndroidView في القوائم الكسولة
إذا كنت تستخدم AndroidView في قائمة Lazy (LazyColumn أو LazyRow أو Pager أو غير ذلك)، ننصحك باستخدام AndroidView
الذي تم تقديمه في الإصدار 1.4.0-rc01. تتيح عملية التحميل الزائد هذه لـ Compose إعادة استخدام مثيل View الأساسي عند إعادة استخدام التركيب الحاوي كما هو، كما هو الحال مع القوائم الكسولة.
تضيف هذه الزيادة في التحميل الزائد AndroidView مَعلمتَين إضافيتَين:
-
onReset: دالة يتم استدعاؤها للإشارة إلى أنّViewسيتم إعادة استخدامه قريبًا. يجب أن تكون هذه القيمة غير فارغة لتفعيل إعادة استخدام العرض. -
onRelease(اختياري): دالة ردّ يتم استدعاؤها للإشارة إلى أنّViewقد خرج من التركيب ولن تتم إعادة استخدامه مرة أخرى.
@Composable fun AndroidViewInLazyList() { LazyColumn { items(100) { index -> AndroidView( modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree factory = { context -> MyView(context) }, update = { view -> view.selectedItem = index }, onReset = { view -> view.clear() } ) } } }
الأجزاء في Compose
استخدِم العنصر القابل للإنشاء AndroidViewBinding لإضافة Fragment في Compose.
يتضمّن AndroidViewBinding معالجة خاصة بالجزء، مثل إزالة الجزء عندما يغادر العنصر القابل للإنشاء التركيب.
يمكنك إجراء ذلك من خلال توسيع ملف XML يحتوي على FragmentContainerView
كعنصر نائب عن Fragment.
على سبيل المثال، إذا كان لديك my_fragment_layout.xml محدّد، يمكنك استخدام رمز مشابه لما يلي مع استبدال سمة XML android:name باسم فئة Fragment:
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container_view" android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.example.compose.snippets.interop.MyFragment" />
يمكنك توسيع هذا الجزء في Compose على النحو التالي:
@Composable fun FragmentInComposeExample() { AndroidViewBinding(MyFragmentLayoutBinding::inflate) { val myFragment = fragmentContainerView.getFragment<MyFragment>() // ... } }
إذا كنت بحاجة إلى استخدام عدة أجزاء في التصميم نفسه، تأكَّد من تحديد معرّف فريد لكل FragmentContainerView.
استدعاء إطار عمل Android من Compose
تعمل Compose ضمن فئات إطار عمل Android. على سبيل المثال، تتم استضافته على فئات Android View، مثل Activity أو Fragment، وقد يستخدم فئات إطار عمل Android، مثل Context أو موارد النظام Service أو BroadcastReceiver.
لمزيد من المعلومات حول موارد النظام، يمكنك الاطّلاع على الموارد في Compose.
Composition Locals
تسمح فئات CompositionLocal بتمرير البيانات ضمنيًا من خلال الدوال القابلة للإنشاء. ويتم عادةً توفيرها بقيمة في عقدة معيّنة من شجرة واجهة المستخدم. ويمكن أن تستخدم العناصر التابعة القابلة للإنشاء هذه القيمة بدون تعريف CompositionLocal كمعلَمة في الدالة القابلة للإنشاء.
يُستخدَم CompositionLocal لنقل قيم أنواع إطار عمل Android في Compose، مثل Context أو Configuration أو View التي يتم فيها استضافة رمز Compose مع LocalContext أو LocalConfiguration أو LocalView المقابل.
يُرجى العِلم أنّ فئات CompositionLocal يتم تحديد بادئتها بـ Local لتسهيل العثور عليها باستخدام ميزة الإكمال التلقائي في بيئة التطوير المتكاملة.
يمكنك الوصول إلى القيمة الحالية لـ CompositionLocal باستخدام السمة current. على سبيل المثال، يعرض الرمز أدناه رسالة إشعار مؤقت من خلال توفير
LocalContext.current في طريقة Toast.makeToast.
@Composable fun ToastGreetingButton(greeting: String) { val context = LocalContext.current Button(onClick = { Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show() }) { Text("Greet") } }
للاطّلاع على مثال أكثر اكتمالاً، راجِع قسم دراسة حالة: BroadcastReceivers في نهاية هذا المستند.
تفاعلات أخرى
إذا لم تكن هناك أداة مساعدة محدّدة للتفاعل الذي تحتاجه، فإنّ أفضل ممارسة هي اتّباع إرشادات Compose العامة، أي تنتقل البيانات إلى الأسفل، وتنتقل الأحداث إلى الأعلى (تمت مناقشة ذلك بالتفصيل في التفكير في Compose). على سبيل المثال، يطلق هذا العنصر القابل للإنشاء نشاطًا مختلفًا:
class OtherInteractionsActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // get data from savedInstanceState setContent { MaterialTheme { ExampleComposable(data, onButtonClick = { startActivity(Intent(this, MyActivity::class.java)) }) } } } } @Composable fun ExampleComposable(data: DataExample, onButtonClick: () -> Unit) { Button(onClick = onButtonClick) { Text(data.title) } }
دراسة حالة: مستقبِلات البث
للحصول على مثال أكثر واقعية للميزات التي قد تحتاج إلى نقلها أو تنفيذها في Compose، ولعرض CompositionLocal والتأثيرات الجانبية، لنفترض أنّه يجب تسجيل BroadcastReceiver من دالة قابلة للإنشاء.
يستفيد الحلّ من LocalContext لاستخدام السياق الحالي، ومن التأثيرات الجانبية rememberUpdatedState وDisposableEffect.
@Composable fun SystemBroadcastReceiver( systemAction: String, onSystemEvent: (intent: Intent?) -> Unit ) { // Grab the current context in this part of the UI tree val context = LocalContext.current // Safely use the latest onSystemEvent lambda passed to the function val currentOnSystemEvent by rememberUpdatedState(onSystemEvent) // If either context or systemAction changes, unregister and register again DisposableEffect(context, systemAction) { val intentFilter = IntentFilter(systemAction) val broadcast = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { currentOnSystemEvent(intent) } } context.registerReceiver(broadcast, intentFilter) // When the effect leaves the Composition, remove the callback onDispose { context.unregisterReceiver(broadcast) } } } @Composable fun HomeScreen() { SystemBroadcastReceiver(Intent.ACTION_BATTERY_CHANGED) { batteryStatus -> val isCharging = /* Get from batteryStatus ... */ true /* Do something if the device is charging */ } /* Rest of the HomeScreen */ }
الخطوات التالية
بعد التعرّف على واجهات برمجة التطبيقات الخاصة بالتوافق عند استخدام Compose في "طرق العرض" والعكس، يمكنك الاطّلاع على صفحة اعتبارات أخرى لمعرفة المزيد.
اقتراحات مخصصة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة
- اعتبارات أخرى
- الآثار الجانبية في Compose
- البيانات ذات النطاق المحلي باستخدام CompositionLocal