میتوانید سلسلهمراتب «نمای 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) } }