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

يمكنك تضمين تسلسل هرمي لعرض 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.

لمزيد من المعلومات عن موارد النظام، يمكنك الاطّلاع على الموارد في ميزة "الإنشاء".

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

تتيح 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 في نهاية هذا المستند.

تفاعلات أخرى

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

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 */
}

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

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