استفاده از «نماها» در «نوشتن»

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

برای افزودن عنصر نما یا سلسله‌مراتب، از AndroidView ترکیب‌پذیر استفاده کنید. ‫AndroidView لامبدایی را می‌پذیرد که View را برمی‌گرداند. AndroidView همچنین update فراخوانی برگشتی‌ای ارائه می‌دهد که وقتی نمای باد می‌شود فراخوانی می‌شود. هرگاه State خوانده‌شده در تغییرات برگشتی تغییر کند، AndroidView دوباره ترکیب می‌شود. ‫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 API که توسط کتابخانه androidx.compose.ui:ui-viewbinding ارائه می‌شود استفاده کنید. برای انجام این کار، پروژه شما باید view binding را فعال کند.

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

‫AndroidView در «فهرست‌های تنبل»

اگر از AndroidView در فهرست تنبل (LazyColumn، LazyRow، Pager، و غیره) استفاده می‌کنید، از سربار AndroidView که در نسخه 1.4.0-rc01 معرفی شده است استفاده کنید. این سربار به «نگارش» اجازه می‌دهد وقتی ترکیب حاوی آن همان‌طور که هست دوباره استفاده می‌شود، از نمونه 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()
                }
            )
        }
    }
}

تکه‌کدها در «نوشتن» (مرحله انتقالی)

برای افزودن Fragment در «نوشتن»، از عنصر ترکیبی AndroidFragment استفاده کنید. ‫AndroidFragment مدیریت خاص قطعه دارد، مثلاً وقتی عنصر ترکیبی ترکیب‌بندی را ترک می‌کند، قطعه را برمی‌دارد.

برای افزودن یک تکه‌کد، از AndroidFragment composable استفاده کنید. یک کلاس Fragment را به AndroidFragment منتقل می‌کنید، که سپس نمونه‌ای از آن کلاس را مستقیماً به ترکیب اضافه می‌کند. AndroidFragment همچنین شیء fragmentState را برای ایجاد AndroidFragment با وضعیت داده‌شده، arguments برای انتقال به قطعه جدید، و یک بازخوان onUpdate که قطعه را از ترکیب ارائه می‌دهد، ارائه می‌دهد. مانند بسیاری از ترکیب‌پذیرهای داخلی دیگر، AndroidFragment پارامتر Modifier را می‌پذیرد که می‌توانید از آن، برای مثال، برای تنظیم موقعیت آن در ترکیب‌پذیر والد استفاده کنید.

در «نوشتن» با AndroidFragment تماس بگیرید به این صورت:

@Composable
fun FragmentInComposeExample() {
    AndroidFragment<MyFragment>()
}

وضعیت چرخه حیات «تکه‌کلاه»

در Fragment 1.9.0 و بالاتر، می‌توانید از پارامتر 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 استفاده کند.

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

ترکیب محلی‌ها

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

از CompositionLocal برای تکثیر مقادیر انواع چارچوب Android در Compose مثل Context، Configuration، یا View که در آن کد Compose با LocalContext، LocalConfiguration، یا LocalView مربوطه میزبانی می‌شود استفاده می‌شود. توجه داشته باشید که CompositionLocal کلاس با Local پیشوندگذاری شده است تا در IDE با تکمیل خودکار بهتر قابل‌کشف باشد.

بااستفاده از خصوصیت current به مقدار فعلی CompositionLocal دسترسی پیدا کنید. برای مثال، کد زیر با ارائه 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 */
}

تعامل‌های دیگر

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

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