W interfejsie Compose możesz uwzględnić hierarchię widoków Androida. To podejście jest
szczególnie przydatne, jeśli chcesz używać elementów interfejsu, które nie są jeszcze dostępne w
Compose, np.
AdView.
Dzięki temu podejściu możesz też ponownie wykorzystać niestandardowe widoki, które zostały zaprojektowane.
Aby uwzględnić element widoku lub hierarchię, użyj komponentu AndroidView
. AndroidView przekazywana jest lambda, która zwraca
View. AndroidView udostępnia też wywołanie zwrotne update, które jest wywoływane, gdy widok jest rozwijany. AndroidView ponownie tworzy kompozycję, gdy zmieni się State odczytany w wywołaniu zwrotnym. AndroidView, podobnie jak wiele innych wbudowanych komponentów, przyjmuje parametr Modifier, którego można użyć np. do ustawienia jego pozycji w komponencie nadrzędnym.
@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() } }
AndroidViewAndroidView
AndroidView z powiązaniem widoku
Aby osadzić układ XML, użyj interfejsu
AndroidViewBinding
API, który jest udostępniany przez bibliotekę androidx.compose.ui:ui-viewbinding. Aby
to zrobić, musisz włączyć powiązanie widoku w projekcie.
@Composable fun AndroidViewBindingExample() { AndroidViewBinding(ExampleLayoutBinding::inflate) { exampleView.setBackgroundColor(Color.GRAY) } }
AndroidView na listach leniwych
Jeśli używasz AndroidView na liście leniwej (LazyColumn, LazyRow,
Pager, itp.), rozważ użycie AndroidView
przeciążenia wprowadzonego w wersji 1.4.0-rc01. To przeciążenie umożliwia Compose ponowne użycie bazowej instancji View, gdy kompozycja zawierająca jest ponownie używana, tak jak w przypadku list leniwych.
To przeciążenie AndroidView dodaje 2 dodatkowe parametry:
onReset– wywołanie zwrotne wywoływane w celu zasygnalizowania, żeViewma zostać ponownie użyty. Aby umożliwić ponowne użycie widoku, musi to być wartość inną niż null.onRelease(opcjonalne) – wywołanie zwrotne wywoływane w celu zasygnalizowania, żeViewopuścił kompozycję i nie będzie już ponownie używany.
@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() } ) } } }
Fragmenty w Compose (etap przejściowy)
Aby dodać Fragment w Compose, użyj komponentu AndroidFragment.
AndroidFragment ma obsługę specyficzną dla fragmentów, np. usuwanie fragmentu, gdy komponent opuszcza kompozycję.
Aby uwzględnić fragment, użyj AndroidFragment
komponentu. Do AndroidFragment przekazujesz klasę Fragment, która następnie dodaje
instancję tej klasy bezpośrednio do kompozycji. AndroidFragment udostępnia też obiekt fragmentState, który umożliwia utworzenie AndroidFragment z danym stanem, arguments do przekazania do nowego fragmentu oraz wywołanie zwrotne onUpdate, które udostępnia fragment z kompozycji. Podobnie jak wiele innych wbudowanych komponentów, AndroidFragment akceptuje parametr Modifier, którego można użyć np. do ustawienia jego pozycji w komponencie nadrzędnym.
Wywołaj AndroidFragment w Compose w ten sposób:
@Composable fun FragmentInComposeExample() { AndroidFragment<MyFragment>() }
Wywoływanie platformy Androida z Compose
Compose działa w klasach platformy Androida. Jest on np. hostowany w klasach widoków Androida, takich jak Activity czy Fragment, i może używać klas platformy Androida, takich jak Context, zasoby systemowe, Service czy BroadcastReceiver.
Więcej informacji o zasobach systemowych znajdziesz w artykule Zasoby w Compose.
Lokale kompozycji
CompositionLocal
klasy umożliwiają niejawne przekazywanie danych przez funkcje komponentów. Zwykle są one udostępniane z wartością w określonym węźle drzewa interfejsu. Wartość ta może być używana przez komponenty potomne bez deklarowania CompositionLocal jako parametru w funkcji typu „composable”.
CompositionLocal służy do propagowania wartości typów platformy Androida w
Compose, takich jak Context, Configuration czy View, w których hostowany jest kod Compose, z odpowiednimi
LocalContext,
LocalConfiguration,
lub
LocalView.
Pamiętaj, że CompositionLocal klasy mają przedrostek Local, aby ułatwić ich znajdowanie za pomocą autouzupełniania w IDE.
Aby uzyskać dostęp do bieżącej wartości CompositionLocal, użyj jej właściwości current. Na przykład poniższy kod wyświetla komunikat toast, przekazując LocalContext.current do metody Toast.makeToast.
@Composable fun ToastGreetingButton(greeting: String) { val context = LocalContext.current Button(onClick = { Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show() }) { Text("Greet") } }
Odbiorniki
Aby zaprezentować CompositionLocal i efekty
uboczne, jeśli
BroadcastReceiver musi zostać zarejestrowany z
funkcji typu „composable”, użyj LocalContext, aby użyć bieżącego kontekstu, oraz
rememberUpdatedState i DisposableEffect efektów ubocznych.
@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 */ }
Inne interakcje
Jeśli nie ma narzędzia zdefiniowanego dla potrzebnej interakcji, najlepszym rozwiązaniem jest przestrzeganie ogólnej zasady Compose: dane przepływają w dół, a zdarzenia w górę (omówionej bardziej szczegółowo w artykule Myślenie w Compose). Na przykład ten komponent uruchamia inną aktywność:
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) } }