Ansichten in „Compose“ verwenden

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. Außerdem können Sie so benutzerdefinierte Ansichten wiederverwenden, die Sie möglicherweise erstellt haben.

Verwenden Sie die zusammensetzbare Funktion AndroidView , um ein Ansichtselement oder eine Hierarchie einzufügen. AndroidView wird eine Lambda-Funktion übergeben, die eine View zurückgibt. AndroidView bietet auch einen update-Callback, der aufgerufen wird, wenn die Ansicht aufgebläht 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. Mit dieser Ü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, dass View wiederverwendet wird. Dieser Wert darf nicht null sein, damit die Ansicht wiederverwendet werden kann.
  • onRelease (optional): Ein Callback, der aufgerufen wird, um zu signalisieren, dass View 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 AndroidFragment-Composable können Sie in Compose eine Fragment hinzufügen. AndroidFragment hat fragmentbezogene Funktionen wie das Entfernen des Fragments, wenn die Composable aus der Komposition entfernt wird.

Verwenden Sie die zusammensetzbare Funktion AndroidFragment, um ein Fragment einzufügen. Sie übergeben eine Fragment-Klasse an AndroidFragment, die dann eine Instanz dieser Klasse direkt in die Komposition einfügt. AndroidFragment stellt auch ein fragmentState-Objekt bereit, 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>()
}

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 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

Mit CompositionLocal-Klassen können Daten implizit über zusammensetzbare Funktionen übergeben werden. 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 denen der Compose-Code gehostet wird, mit den entsprechenden LocalContext-, LocalConfiguration- oder LocalView-Objekten 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 Compose-Denkweise 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: Angenommen, ein BroadcastReceiver muss über eine zusammensetzbare Funktion registriert werden.

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 kennengelernt haben, können Sie sich auf der Seite Weitere Überlegungen informieren.