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
stellt auch einen update
-Callback bereit, der aufgerufen wird, wenn die Ansicht aufgebläht wird. Das AndroidView
wird neu zusammengesetzt, wenn sich ein State
-Lesevorgang innerhalb des Callbacks ändert. 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 in Ihrem Projekt die Ansichtsbindung 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. Aufgrund dieser Überlast kann Compose die zugrunde liegende View
-Instanz wiederverwenden, wenn die enthaltene Komposition wiederverwendet wird, wie es bei Lazy-Listen der Fall ist.
Diese Überlastung von AndroidView
fügt zwei zusätzliche Parameter hinzu:
onReset
: Ein Callback, der aufgerufen wird, um zu signalisieren, dassView
gleich verwendet 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
Mit der zusammensetzbaren Funktion AndroidViewBinding
können Sie in „Schreiben“ eine Fragment
hinzufü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.
Zusammensetzung von Ortsansässigen
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.
Mit CompositionLocal
werden Werte für Android-Framework-Typen in Composer wie Context
, Configuration
oder die View
weitergegeben, in denen der Compose-Code mit dem 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.
Sie können über das Attribut current
auf den aktuellen Wert einer 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: Rundfunkempfä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.
Die Lösung nutzt LocalContext
, 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