استخدام طرق العرض في "إنشاء"

يمكنك تضمين تسلسل هرمي لعرض Android في واجهة مستخدم Compose. يكون هذا النهج مفعّلاً بشكلٍ خاص إذا كنت تريد استخدام عناصر واجهة مستخدِم غير متاحة بعد في ميزة الإنشاء، مثل AdView. يتيح لك هذا الأسلوب أيضًا إعادة استخدام الاطِّلاعات المخصّصة التي ربما تكون قد صمّمتها.

لتضمين عنصر عرض أو تسلسل هرمي، استخدِم العنصر القابل للتجميع AndroidView . يتم تمرير دالة LAMBDA إلى AndroidView لعرض View. يوفّر AndroidView أيضًا دالة update ردّ اتصال يتمّ استدعاؤها عند تضخيم طريقة العرض. تتم إعادة تركيب AndroidView كلما تغيّر State الذي تم قراءته في ردّ الاتصال. يأخذ العنصر AndroidView، مثل العديد من العناصر القابلة للتجميع المضمّنة الأخرى، مَعلمة Modifier التي يمكن استخدامها، مثلاً، لضبط موضعه في العنصر القابل للتجميع الرئيسي.

@Composable
fun CustomView() {
    var selectedItem by remember { mutableStateOf(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 في قائمة بطيئة التحميل (LazyColumn أو LazyRow أو Pager أو غير ذلك)، ننصحك باستخدام التحميل الزائد AndroidView الذي تم تقديمه في الإصدار 1.4.0-rc01. تسمح هذه التحميلات الزائدة لـ Compose بإعادة استخدام مثيل View الأساسي عند إعادة استخدام التركيب المُحتوي كما هو الحال في القوائم البطيئة.

تضيف هذه الوظيفة الزائدة لـ AndroidView مَعلمتَين إضافيتين:

  • onReset: دالة يتمّ استدعاؤها للإشارة إلى أنّه سيتم إعادة استخدام View. يجب أن يكون هذا الحقل غير فارغ لتفعيل إعادة استخدام "العرض".
  • onRelease (اختياري) - دالة استدعاء يتمّ استدعاؤها للإشارة إلى أنّ View قد خرج من المكوّن ولن تتم إعادة استخدامه مرة أخرى.

@OptIn(ExperimentalComposeUiApi::class)
@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()
                }
            )
        }
    }
}

الأجزاء في ميزة "الإنشاء"

استخدِم العنصر القابل للتجميع AndroidViewBinding لإضافة Fragment في ميزة "الإنشاء". تتضمّن 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" />

وسِّع هذا المقتطف في ميزة "الإنشاء" على النحو التالي:

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

ترجمة المقطوعة الموسيقية

تتيح فئات 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")
    }
}

للحصول على مثال أكثر اكتمالاً، اطّلِع على قسم دراسة الحالة: BroadcastReceivers في نهاية هذا المستند.

تفاعلات أخرى

إذا لم تكن هناك خدمة محدّدة للتفاعل الذي تحتاجه، فإنّ أفضل الممارسات هي اتّباع الإرشادات العامة لإنشاء الرسائل، وهي تدفق البيانات للأسفل وتدفق الأحداث للأعلى (تمّت مناقشة ذلك بالتفصيل في مقالة التفكير في 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)
    }
}

دراسة حالة: أجهزة استقبال البث

للحصول على مثال أكثر واقعية للميزات التي قد تحتاج إلى نقلها أو تنفيذها في أداة "الإنشاء"، ولعرض 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 */
}

الخطوات التالية

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