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

يمكنك تضمين هيكلية طرق عرض 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)
    }
}