В Compose UI можно включить иерархию Android View. Этот подход особенно полезен, если вы хотите использовать элементы пользовательского интерфейса, которые еще недоступны в Compose, например, AdView . Он также позволяет повторно использовать созданные вами пользовательские представления.
To include a view element or hierarchy, use the AndroidView composable. AndroidView is passed a lambda that returns a View . AndroidView also provides an update callback that is called when the view is inflated. The AndroidView recomposes whenever a State read within the callback changes. AndroidView , like many other built-in composables, takes a Modifier parameter that can be used, for example, to set its position in the parent composable.
@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-макета используйте API 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 добавляет 2 дополнительных параметра:
-
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() } ) } } }
Фрагменты в композиции (переходный этап)
Используйте компонент AndroidFragment для добавления Fragment в Compose. AndroidFragment имеет специфические для фрагментов механизмы обработки, например, удаление фрагмента, когда компонент покидает Compose.
To include a fragment, use the AndroidFragment composable. You pass a Fragment class to AndroidFragment , which then adds an instance of that class directly into the composition. AndroidFragment also provides a fragmentState object to create the AndroidFragment with a given state, arguments to pass into the new fragment, and an onUpdate callback that provides the fragment from the composition. Like many other built-in composables, AndroidFragment accepts a Modifier parameter that you can use, for example, to set its position in the parent composable.
Вызовите AndroidFragment в Compose следующим образом:
@Composable fun FragmentInComposeExample() { AndroidFragment<MyFragment>() }
Состояние жизненного цикла фрагмента крышки
В версиях Fragment 1.9.0 и выше можно использовать параметр maxLifecycle для ограничения состояния жизненного цикла встроенного Fragment .
For example, in a HorizontalPager , you can dynamically set maxLifecycle to RESUMED only when the corresponding page is active, keeping offscreen pages capped at STARTED . When the user navigates to another page, the previous page's fragment cap becomes STARTED . This pauses or cancels workloads scoped to RESUMED (such as coroutines running in repeatOnLifecycle(RESUMED) ), preventing offscreen pages from performing foreground-only work while keeping their UI initialized at 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, таких как 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 побочных эффектах UpdatedState и 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) } }