استفاده از Views در Compose

می توانید یک سلسله مراتب Android View را در یک رابط کاربری Compose اضافه کنید. اگر می‌خواهید از عناصر رابط کاربری استفاده کنید که هنوز در Compose در دسترس نیستند، مانند AdView ، این رویکرد بسیار مفید است. این رویکرد همچنین به شما امکان می دهد از نماهای سفارشی که ممکن است طراحی کرده اید مجددا استفاده کنید.

برای گنجاندن یک عنصر view یا سلسله مراتب، از AndroidView composable استفاده کنید. AndroidView یک لامبدا ارسال می شود که یک View برمی گرداند. AndroidView همچنین یک پاسخ update ارائه می‌دهد که وقتی نما باد شده است، فراخوانی می‌شود. AndroidView هر زمان که State خوانده شده در پاسخ به تماس تغییر کند، دوباره ترکیب می شود. AndroidView ، مانند بسیاری دیگر از اجزای سازنده داخلی، یک پارامتر Modifier می گیرد که می تواند به عنوان مثال، برای تنظیم موقعیت آن در Composable والد استفاده شود.

@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 با view binding

برای جاسازی یک طرح بندی XML، از AndroidViewBinding API استفاده کنید که توسط کتابخانه androidx.compose.ui:ui-viewbinding ارائه شده است. برای انجام این کار، پروژه شما باید view binding را فعال کند.

@Composable
fun AndroidViewBindingExample() {
    AndroidViewBinding(ExampleLayoutBinding::inflate) {
        exampleView.setBackgroundColor(Color.GRAY)
    }
}

AndroidView در لیست های تنبل

اگر از AndroidView در لیست Lazy استفاده می کنید ( LazyColumn ، LazyRow ، Pager ، و غیره)، از اضافه بار AndroidView که در نسخه 1.4.0-rc01 معرفی شده است استفاده کنید. این اضافه بار به Compose اجازه می‌دهد تا در صورت استفاده مجدد از ترکیب حاوی، مانند لیست‌های Lazy، از نمونه View اصلی استفاده کند.

این اضافه بار AndroidView 2 پارامتر اضافی اضافه می کند:

  • 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 composable برای افزودن یک Fragment در Compose استفاده کنید. AndroidViewBinding دارای مدیریت خاص قطعه است، مانند حذف قطعه زمانی که composable از ترکیب خارج می شود.

این کار را با باد کردن یک XML حاوی FragmentContainerView به عنوان نگهدارنده Fragment خود انجام دهید.

برای مثال، اگر my_fragment_layout.xml را تعریف کرده‌اید، می‌توانید از کدی مانند این استفاده کنید، در حالی که ویژگی android:name XML را با نام کلاس 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 تعریف کرده اید.

فراخوانی فریم ورک اندروید از Compose

Compose در کلاس های فریمورک اندروید عمل می کند. برای مثال، در کلاس‌های Android View، مانند Activity یا Fragment ، میزبانی می‌شود و ممکن است از کلاس‌های چارچوب Android مانند Context ، منابع سیستم، Service یا BroadcastReceiver استفاده کند.

برای کسب اطلاعات بیشتر در مورد منابع سیستم، به منابع در نوشتن مراجعه کنید.

ترکیب محلی ها

کلاس‌های CompositionLocal اجازه می‌دهند تا داده‌ها را به طور ضمنی از طریق توابع ترکیب‌پذیر منتقل کنند. آنها معمولاً با یک مقدار در گره خاصی از درخت UI ارائه می شوند. این مقدار می تواند توسط نوادگان قابل ترکیب آن بدون اعلام CompositionLocal به عنوان یک پارامتر در تابع composable استفاده شود.

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")
    }
}

برای مثال کامل‌تر، به بخش Case Study: BroadcastReceivers در انتهای این سند نگاهی بیندازید.

سایر تعاملات

اگر ابزاری برای تعاملی که نیاز دارید تعریف نشده است، بهترین کار این است که از دستورالعمل کلی نوشتن پیروی کنید، داده‌ها پایین می‌آیند، رویدادها جریان می‌یابند (که در Thinking in Compose به طور مفصل‌تر بحث شده است). به عنوان مثال، این composable یک فعالیت متفاوت را راه اندازی می کند:

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 باید از یک تابع composable ثبت شود.

این راه حل از 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 */
}

مراحل بعدی

اکنون که APIهای قابلیت همکاری هنگام استفاده از Compose در Views و بالعکس را می‌شناسید، برای کسب اطلاعات بیشتر، صفحه سایر ملاحظات را بررسی کنید.

{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}