Sie können eine Android-Ansichtshierarchie in eine Compose-Benutzeroberfläche einbinden. Dieser Ansatz ist besonders nützlich, wenn Sie UI-Elemente verwenden möchten, die in Compose noch nicht verfügbar sind, z. B. AdView
.
Außerdem können Sie so benutzerdefinierte Ansichten wiederverwenden, die Sie möglicherweise erstellt haben.
Wenn Sie ein Ansichtselement oder eine Hierarchie einfügen möchten, verwenden Sie das AndroidView
-Element „composable“. AndroidView
wird ein Lambda übergeben, das eine View
zurückgibt. AndroidView
bietet auch einen update
-Callback, der aufgerufen wird, wenn die Ansicht maximiert wird. Die AndroidView
wird neu erstellt, wenn sich eine State
ändert, die im Rückruf gelesen wird. AndroidView
nimmt wie viele andere integrierte Elemente den Parameter Modifier
an, mit dem sich beispielsweise die Position im übergeordneten Element festlegen lässt.
@Composable fun CustomView() { var selectedItem by remember { mutableStateOf(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 du ein XML-Layout einbetten möchtest, verwende die AndroidViewBinding
API, die von der androidx.compose.ui:ui-viewbinding
-Bibliothek bereitgestellt wird. Dazu muss die Ansichtsbindung in Ihrem Projekt aktiviert sein.
@Composable fun AndroidViewBindingExample() { AndroidViewBinding(ExampleLayoutBinding::inflate) { exampleView.setBackgroundColor(Color.GRAY) } }
AndroidView
in Lazy-Listen
Wenn Sie AndroidView
in einer Lazy-Liste (LazyColumn
, LazyRow
, Pager
usw.) verwenden, sollten Sie die in Version 1.4.0-rc01 eingeführte Überladung von AndroidView
verwenden. Mit dieser Überladung kann Compose die zugrunde liegende View
-Instanz wiederverwenden, wenn die enthaltene Komposition wiederverwendet wird, wie es bei Lazy-Listen der Fall ist.
Bei dieser Überladung von AndroidView
werden zwei zusätzliche Parameter hinzugefügt:
onReset
: Ein Callback, der aufgerufen wird, um anzuzeigen, dass derView
wiederverwendet werden soll. Dieser Wert darf nicht null sein, damit die Wiederverwendung der Ansicht möglich ist.onRelease
(optional): Ein Callback, der aufgerufen wird, um anzuzeigen, dass dieView
die Komposition verlassen hat und nicht wiederverwendet wird.
@OptIn(ExperimentalComposeUiApi::class) @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
Verwenden Sie das AndroidViewBinding
-Element, um in Compose ein Fragment
hinzuzufügen.
AndroidViewBinding
hat fragmentspezifische Funktionen, z. B. das Entfernen des Fragments, wenn das Composed-Element die Komposition verlässt.
Dazu müssen Sie eine XML-Datei mit einer FragmentContainerView
als Inhaber Ihrer Fragment
aufblähen.
Wenn Sie beispielsweise my_fragment_layout.xml
definiert haben, können Sie Code wie diesen verwenden und dabei das XML-Attribut android:name
durch den Klassennamen Ihrer Fragment
ersetzen:
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container_view" android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.example.compose.snippets.interop.MyFragment" />
Maximieren Sie dieses Fragment in „Compose“ so:
@Composable fun FragmentInComposeExample() { AndroidViewBinding(MyFragmentLayoutBinding::inflate) { val myFragment = fragmentContainerView.getFragment<MyFragment>() // ... } }
Wenn Sie mehrere Fragmente im selben Layout verwenden möchten, müssen Sie für jede FragmentContainerView
eine eindeutige ID definieren.
Android-Framework über Compose aufrufen
Compose wird in den Android-Framework-Klassen ausgeführt. Sie wird beispielsweise in Android View-Klassen wie Activity
oder Fragment
gehostet und kann Android-Framework-Klassen wie Context
, Systemressourcen, Service
oder BroadcastReceiver
verwenden.
Weitere Informationen zu Systemressourcen finden Sie unter Ressourcen in Compose.
Komposition – Lokale
Mit CompositionLocal
-Klassen können Daten implizit über kombinierbare Funktionen übergeben werden. Sie werden in der Regel in einem bestimmten Knoten des UI-Baums mit einem Wert versehen. Dieser Wert kann von den untergeordneten Elementen verwendet werden, ohne dass CompositionLocal
als Parameter in der zusammensetzbaren Funktion deklariert werden muss.
CompositionLocal
wird verwendet, um Werte für Android-Frameworktypen in Compose zu übertragen, z. B. Context
, Configuration
oder View
, in dem der Compose-Code mit der entsprechenden LocalContext
, LocalConfiguration
oder LocalView
gehostet wird.
CompositionLocal
-Klassen haben das Präfix Local
, damit sie bei der automatischen Vervollständigung in der IDE leichter gefunden werden.
Über die Property current
können Sie auf den aktuellen Wert eines CompositionLocal
zugreifen. Im folgenden Code wird beispielsweise eine Toast-Nachricht angezeigt, indem LocalContext.current
in die Methode Toast.makeToast
übergeben wird.
@Composable fun ToastGreetingButton(greeting: String) { val context = LocalContext.current Button(onClick = { Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show() }) { Text("Greet") } }
Ein vollständigeres Beispiel finden Sie am Ende dieses Dokuments im Abschnitt Fallstudie: BroadcastReceiver.
Sonstige Interaktionen
Wenn für die gewünschte Interaktion kein Dienstprogramm definiert ist, empfiehlt es sich, der allgemeinen Compose-Richtlinie zu folgen: Daten fließen nach unten, Ereignisse nach oben. Weitere Informationen finden Sie unter In Compose denken. Mit diesem Composeable wird beispielsweise eine andere Aktivität gestartet:
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) } }
Fallstudie: Broadcast-Empfänger
Ein realistischeres Beispiel für Funktionen, die Sie in Compose migrieren oder implementieren möchten, und um CompositionLocal
und Nebeneffekte zu veranschaulichen: Angenommen, eine BroadcastReceiver
muss über eine kompostierbare Funktion registriert werden.
In der Lösung wird LocalContext
verwendet, um den aktuellen Kontext zu verwenden, sowie die Nebenwirkungen 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 */ }
Nächste Schritte
Nachdem Sie nun die APIs zur Interoperabilität kennen, die bei der Verwendung von Compose in Ansichten und umgekehrt verwendet werden, können Sie auf der Seite Weitere Überlegungen weitere Informationen finden.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Weitere Hinweise
- Nebeneffekte in Compose
- Daten auf lokaler Ebene mit CompositionLocal