Sie können eine Android-Ansichtshierarchie in eine Compose-UI 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
.
So können Sie auch benutzerdefinierte Ansichten wiederverwenden, die Sie möglicherweise erstellt haben.
Wenn Sie ein Ansichtselement oder eine Hierarchie einfügen möchten, verwenden Sie die zusammensetzbare Funktion AndroidView
. AndroidView
wird eine Lambda-Funktion übergeben, die eine View
zurückgibt. AndroidView
bietet auch einen update
-Callback, der aufgerufen wird, wenn die Ansicht instanziiert wird. Die AndroidView
wird neu zusammengesetzt, wenn sich ein State
ändert, der im Callback gelesen wird. AndroidView
akzeptiert 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 View Binding
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 View Binding aktiviert sein.
@Composable fun AndroidViewBindingExample() { AndroidViewBinding(ExampleLayoutBinding::inflate) { exampleView.setBackgroundColor(Color.GRAY) } }
AndroidView
in Lazy Lists
Wenn Sie ein AndroidView
in einer Lazy-Liste (LazyColumn
, LazyRow
, Pager
usw.) verwenden, sollten Sie die in Version 1.4.0-rc01 eingeführte AndroidView
-Überladung verwenden. Durch diese Überladung kann Compose die zugrunde liegende View
-Instanz wiederverwenden, wenn die enthaltende Komposition wiederverwendet wird, wie es bei Lazy-Listen der Fall ist.
Durch diese Überladung von AndroidView
werden zwei zusätzliche Parameter hinzugefügt:
onReset
: Ein Callback, der aufgerufen wird, um zu signalisieren, dassView
demnächst wiederverwendet wird. Dieser Wert darf nicht null sein, damit die Ansicht wiederverwendet werden kann.onRelease
(optional): Ein Callback, der aufgerufen wird, um zu signalisieren, dassView
die 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
Mit der AndroidViewBinding
-Composable können Sie in Compose eine Fragment
hinzufügen.
AndroidViewBinding
hat fragmentbezogene Funktionen wie das Entfernen des Fragments, wenn die Composable aus der Komposition entfernt wird.
Dazu müssen Sie ein XML mit einem FragmentContainerView
als Platzhalter für Ihre 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 von 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" />
So wird dieses Fragment in Compose eingefügt:
@Composable fun FragmentInComposeExample() { AndroidViewBinding(MyFragmentLayoutBinding::inflate) { val myFragment = fragmentContainerView.getFragment<MyFragment>() // ... } }
Wenn Sie mehrere Fragmente im selben Layout verwenden müssen, müssen Sie für jedes FragmentContainerView
eine eindeutige ID definieren.
Android-Framework über Compose aufrufen
Compose funktioniert innerhalb der Android-Framework-Klassen. Sie wird beispielsweise in Android View-Klassen wie Activity
oder Fragment
gehostet und verwendet möglicherweise Android-Framework-Klassen wie Context
, Systemressourcen wie Service
oder BroadcastReceiver
.
Weitere Informationen zu Systemressourcen finden Sie unter Ressourcen in Compose.
Lokale Kompositionen
CompositionLocal
-Klassen ermöglichen das implizite Übergeben von Daten durch zusammensetzbare Funktionen. Sie haben in der Regel einen Wert in einem bestimmten Knoten des UI-Baums. Dieser Wert kann von den zusammensetzbaren Nachfolgern verwendet werden, ohne dass CompositionLocal
als Parameter in der zusammensetzbaren Funktion deklariert werden muss.
CompositionLocal
wird verwendet, um Werte für Android-Framework-Typen in Compose wie Context
, Configuration
oder View
, in dem der Compose-Code gehostet wird, mit den entsprechenden LocalContext
-, LocalConfiguration
- oder LocalView
-Werten zu übertragen.
CompositionLocal
-Klassen haben das Präfix Local
, damit sie in der IDE leichter über die automatische Vervollständigung gefunden werden können.
Sie können auf den aktuellen Wert eines CompositionLocal
zugreifen, indem Sie das Attribut current
verwenden. 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") } }
Ein vollständigeres Beispiel finden Sie am Ende dieses Dokuments im Abschnitt Fallstudie: BroadcastReceiver.
Andere Interaktionen
Wenn für die benötigte Interaktion kein Utility definiert ist, sollten Sie der allgemeinen Compose-Richtlinie Daten fließen nach unten, Ereignisse nach oben folgen, die in Thinking in Compose ausführlicher beschrieben wird. Mit diesem Composable 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 möglicherweise in Compose migrieren oder implementieren möchten, und um CompositionLocal
und Nebeneffekte zu veranschaulichen, ist die Registrierung eines BroadcastReceiver
aus einer zusammensetzbaren Funktion.
Bei der Lösung wird LocalContext
verwendet, um den aktuellen Kontext zu nutzen, sowie 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 */ }
Nächste Schritte
Nachdem Sie nun die Interoperabilitäts-APIs für die Verwendung von Compose in Views und umgekehrt kennen, können Sie auf der Seite Weitere Überlegungen mehr erfahren.
Empfehlungen für dich
- Hinweis: Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Weitere Überlegungen
- Nebeneffekte in Compose
- Lokal begrenzte Daten mit CompositionLocal