يمكنك تضمين هيكلية طرق عرض Android في واجهة مستخدم 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() } ) } } }
Fragments in Compose (Transitionary Step)
استخدِم الدالة المركّبة AndroidFragment لإضافة Fragment في Compose.
يتضمّن AndroidFragment معالجة خاصة بالمقاطع، مثل إزالة المقطع عندما تغادر الدالة المركّبة التركيب.
لتضمين جزء، استخدِم الدالة المركّبة AndroidFragment. يمكنك تمرير فئة Fragment إلى AndroidFragment، والتي تضيف بعد ذلك
مثيلاً لتلك الفئة مباشرةً إلى التركيب. توفّر AndroidFragment أيضًا
عنصر fragmentState لإنشاء AndroidFragment بحالة
محدّدة، وarguments لتمريرها إلى الجزء الجديد، ودالة استدعاء onUpdate
توفّر الجزء من التركيب. مثل العديد من الدوال المركّبة المضمّنة الأخرى، تقبل الدالة AndroidFragment مَعلمة Modifier يمكنك استخدامها، على سبيل المثال، لضبط موضعها في الدالة المركّبة الرئيسية.
يمكنك استدعاء AndroidFragment في Compose على النحو التالي:
@Composable fun FragmentInComposeExample() { AndroidFragment<MyFragment>() }
حالة مرحلة النشاط في Cap Fragment
في الإصدار 1.9.0 من Fragment والإصدارات الأحدث، يمكنك استخدام المَعلمة maxLifecycle
لتحديد حالة مراحل النشاط في Fragment المضمّن.
على سبيل المثال، في HorizontalPager، يمكنك ضبط maxLifecycle ديناميكيًا على RESUMED فقط عندما تكون الصفحة المقابلة نشطة، مع إبقاء الصفحات خارج الشاشة محدودة بـ STARTED. عندما ينتقل المستخدم إلى صفحة أخرى، يصبح الحدّ الأقصى لعدد الأجزاء في الصفحة السابقة STARTED. يؤدي ذلك إلى إيقاف أعباء العمل مؤقتًا أو إلغائها
ضمن نطاق RESUMED (مثل الكوروتين التي تعمل في
repeatOnLifecycle(RESUMED))، ما يمنع الصفحات خارج الشاشة من تنفيذ
العمل في المقدّمة فقط مع الحفاظ على تهيئة واجهة المستخدم الخاصة بها في STARTED:
HorizontalPager(state = pagerState) { page -> // Dynamically cap the lifecycle state based on whether the page is selected val maxLifecycle = if (pagerState.settledPage == page) { Lifecycle.State.RESUMED } else { Lifecycle.State.STARTED } when (page) { 0 -> AndroidFragment<HomeFragment>(maxLifecycle = maxLifecycle) 1 -> AndroidFragment<LibraryFragment>(maxLifecycle = maxLifecycle) /* Other pages and corresponding fragments */ } }
استدعاء إطار عمل Android من Compose
تعمل Compose ضمن فئات إطار عمل Android. على سبيل المثال، تتم استضافته
على فئات Android View، مثل Activity أو Fragment، وقد يستخدم فئات
إطار عمل Android مثل Context أو موارد النظام
أو Service أو BroadcastReceiver.
لمزيد من المعلومات حول موارد النظام، يُرجى الاطّلاع على الموارد في Compose.
المقطوعات الموسيقية المحلية
تتيح فئات CompositionLocal تمرير البيانات ضمنيًا من خلال الدوال المركّبة. ويتم عادةً تزويدها بقيمة في عقدة معيّنة من شجرة واجهة المستخدم. ويمكن استخدام هذه القيمة من خلال العناصر الفرعية المركّبة بدون تعريف CompositionLocal كمَعلمة في الدالة المركّبة.
يُستخدَم CompositionLocal لنشر قيم أنواع إطار عمل Android في
Compose، مثل Context أو Configuration أو View التي تتم استضافة رمز Compose
فيها مع
LocalContext
أو
LocalConfiguration
أو
LocalView المقابلة.
يُرجى العِلم أنّ فئات CompositionLocal تبدأ بـ Local لتسهيل
العثور عليها من خلال ميزة الإكمال التلقائي في بيئة التطوير المتكاملة (IDE).
يمكنك الوصول إلى القيمة الحالية لـ 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") } }
مستقبِلات البث
لعرض 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 العامة، تدفق البيانات لأسفل، وتدفق الأحداث لأعلى (تمت مناقشتها بمزيد من التفصيل في التفكير في 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) } }