Sie können eine Android-Ansichtshierarchie in eine Compose-Benutzeroberfläche einfügen. Dieser Ansatz ist besonders nützlich, wenn Sie UI-Elemente verwenden möchten, die in Compose noch nicht verfügbar sind, z. B. AdView.
Mit diesem Ansatz können Sie auch benutzerdefinierte Ansichten wiederverwenden, die Sie möglicherweise entworfen haben.
Wenn Sie ein Ansichtselement oder eine Hierarchie einbinden möchten, verwenden Sie die komponierbare Funktion AndroidView
. An AndroidView wird ein Lambda übergeben, das ein View zurückgibt. AndroidView bietet auch einen update-Callback, der aufgerufen wird, wenn die Ansicht aufgebläht wird. Die AndroidView wird immer dann neu zusammengesetzt, wenn sich ein State-Wert ändert, der im Callback gelesen wird. AndroidView verwendet wie viele andere integrierte Composables einen Modifier-Parameter, mit dem beispielsweise die Position im übergeordneten Composable festgelegt werden kann.
@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 mit Ansichtsbindung
Wenn Sie ein XML-Layout einbetten möchten, verwenden Sie die API AndroidViewBinding, die von der Bibliothek androidx.compose.ui:ui-viewbinding bereitgestellt wird. Dazu muss in Ihrem Projekt die Ansichtsbindung aktiviert sein.
@Composable fun AndroidViewBindingExample() { AndroidViewBinding(ExampleLayoutBinding::inflate) { exampleView.setBackgroundColor(Color.GRAY) } }
AndroidView in Lazy-Listen
Wenn Sie einen AndroidView in einer Lazy-Liste (LazyColumn, LazyRow, Pager usw.) verwenden, sollten Sie die Überladung AndroidView verwenden, die in Version 1.4.0-rc01 eingeführt wurde. Diese Überladung ermöglicht es Compose, die zugrunde liegende View-Instanz wiederzuverwenden, wenn die enthaltende Komposition wiederverwendet wird, wie es bei Lazy-Listen der Fall ist.
Diese Überladung von AndroidView fügt zwei zusätzliche Parameter hinzu:
onReset: Ein Callback, der aufgerufen wird, um zu signalisieren, dass dieViewwiederverwendet wird. Dieser Wert darf nicht null sein, damit die Wiederverwendung von Ansichten aktiviert werden kann.onRelease(optional): Ein Callback, der aufgerufen wird, um zu signalisieren, dass dieViewdie Komposition verlassen hat und nicht wiederverwendet wird.
@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() } ) } } }
Fragmente in Compose (Übergangsschritt)
Verwenden Sie die komponierbare Funktion AndroidFragment, um in Compose ein Fragment hinzuzufügen.
AndroidFragment bietet eine fragmentspezifische Verarbeitung, z. B. das Entfernen des Fragments, wenn die zusammensetzbare Funktion die Komposition verlässt.
Wenn Sie ein Fragment einfügen möchten, verwenden Sie die komponierbare Funktion AndroidFragment. Sie übergeben eine Fragment-Klasse an AndroidFragment, wodurch eine Instanz dieser Klasse direkt in die Komposition eingefügt wird. AndroidFragment bietet auch ein fragmentState-Objekt, um das AndroidFragment mit einem bestimmten Status zu erstellen, arguments, das an das neue Fragment übergeben werden soll, und einen onUpdate-Callback, der das Fragment aus der Komposition bereitstellt. Wie viele andere integrierte Composables akzeptiert AndroidFragment einen Modifier-Parameter, mit dem Sie beispielsweise die Position im übergeordneten Composable festlegen können.
Rufen Sie AndroidFragment in Compose so auf:
@Composable fun FragmentInComposeExample() { AndroidFragment<MyFragment>() }
Lebenszyklusstatus des Cap-Fragments
In Fragment 1.9.0 und höher können Sie den Parameter maxLifecycle verwenden, um den Lebenszyklusstatus des eingebetteten Fragment zu begrenzen.
In einem HorizontalPager können Sie beispielsweise maxLifecycle nur dann dynamisch auf RESUMED festlegen, wenn die entsprechende Seite aktiv ist. Für Seiten, die nicht auf dem Bildschirm angezeigt werden, wird die Anzahl auf STARTED begrenzt. Wenn der Nutzer zu einer anderen Seite wechselt, wird die Fragmentbegrenzung der vorherigen Seite auf STARTED gesetzt. Dadurch werden Arbeitslasten im Bereich RESUMED pausiert oder abgebrochen (z. B. Koroutinen, die in repeatOnLifecycle(RESUMED) ausgeführt werden). So wird verhindert, dass Seiten, die nicht auf dem Bildschirm angezeigt werden, nur im Vordergrund ausgeführt werden, während ihre Benutzeroberfläche bei STARTED initialisiert bleibt:
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-Framework über Compose aufrufen
Compose arbeitet innerhalb der Android-Framework-Klassen. Sie wird beispielsweise in Android-Ansichtsklassen wie Activity oder Fragment gehostet und verwendet möglicherweise Android-Framework-Klassen wie Context, Systemressourcen, Service oder BroadcastReceiver.
Weitere Informationen zu Systemressourcen finden Sie unter Ressourcen in Compose.
Kompositions-Locals
Mit CompositionLocal-Klassen können Daten implizit über zusammensetzbare Funktionen übergeben werden. Sie werden normalerweise mit einem Wert in einem bestimmten Knoten des UI-Baums bereitgestellt. Dieser Wert kann von den zusammensetzbaren Nachfolgern verwendet werden, ohne dass der CompositionLocal als Parameter in der zusammensetzbaren Funktion deklariert werden muss.
CompositionLocal wird verwendet, um Werte für Android-Framework-Typen in Compose weiterzugeben, z. B. Context, Configuration oder die View, in der der Compose-Code mit dem entsprechenden LocalContext, LocalConfiguration oder LocalView gehostet wird.
Beachten Sie, dass CompositionLocal-Klassen das Präfix Local haben, damit sie mit der automatischen Vervollständigung in der IDE besser gefunden werden können.
Greifen Sie mit dem Attribut current auf den aktuellen Wert eines CompositionLocal zu. Im folgenden Code wird beispielsweise eine Toast-Nachricht angezeigt, indem LocalContext.current in die Methode Toast.makeToast eingefügt wird.
@Composable fun ToastGreetingButton(greeting: String) { val context = LocalContext.current Button(onClick = { Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show() }) { Text("Greet") } }
Übertragungsempfänger
Um CompositionLocal und Nebeneffekte zu demonstrieren, wird, wenn ein BroadcastReceiver von einer zusammensetzbaren Funktion registriert werden muss, LocalContext verwendet, um den aktuellen Kontext zu verwenden, und die Nebeneffekte rememberUpdatedState und 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 */ }
Andere Interaktionen
Wenn für die gewünschte Interaktion kein Dienstprogramm definiert ist, empfiehlt es sich, die allgemeine Compose-Richtlinie Daten fließen nach unten, Ereignisse nach oben zu befolgen (ausführlicher beschrieben unter In Compose denken). Dieses Composable startet beispielsweise eine andere Aktivität:
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) } }