Utiliser les vues dans Compose

Vous pouvez inclure une hiérarchie des vues Android dans une interface utilisateur Compose. Cette approche est particulièrement utile si vous souhaitez utiliser des éléments d'interface utilisateur qui ne sont pas encore disponibles dans Compose, comme AdView. Cela vous permet également de réutiliser des vues personnalisées.

Pour inclure un élément ou une hiérarchie de vues, utilisez le AndroidView composable. AndroidView reçoit un lambda qui renvoie un View. AndroidView fournit également un rappel update, qui est appelé lorsque la vue est gonflée. AndroidView se recompose chaque fois qu'une lecture State du rappel change. Comme de nombreux autres composables intégrés, AndroidView utilise un paramètre Modifier qui peut servir, par exemple, à définir sa position dans le composable parent.

@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 avec liaison de vue

Pour intégrer une mise en page XML, utilisez l' AndroidViewBinding API fournie par la androidx.compose.ui:ui-viewbinding bibliothèque. Pour ce faire, votre projet doit activer la liaison de vue.

@Composable
fun AndroidViewBindingExample() {
    AndroidViewBinding(ExampleLayoutBinding::inflate) {
        exampleView.setBackgroundColor(Color.GRAY)
    }
}

AndroidView dans les listes différées

Si vous utilisez un AndroidView dans une liste différée (LazyColumn, LazyRow, Pager, etc.), envisagez d'utiliser la AndroidView surcharge introduite dans la version 1.4.0-rc01. Cette surcharge permet à Compose de réutiliser l'instance View sous-jacente lorsque la composition contenant est réutilisée, comme c'est le cas pour les listes différées.

Cette surcharge de AndroidView ajoute deux paramètres supplémentaires :

  • onReset : rappel appelé pour signaler que le View est sur le point d'être réutilisé. Cette valeur doit être non nulle pour activer la réutilisation de la vue.
  • onRelease (facultatif) : rappel appelé pour signaler que la View a quitté la composition et ne sera plus réutilisée.

@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()
                }
            )
        }
    }
}

Fragments dans Compose

Utilisez le composable AndroidFragment pour ajouter un Fragment dans Compose. AndroidFragment offre une gestion spécifique au fragment, comme la suppression du fragment lorsque le composable quitte la composition.

Pour inclure un fragment, utilisez le AndroidFragment composable. Vous transmettez une classe Fragment à AndroidFragment, qui ajoute ensuite une instance de cette classe directement dans la composition. AndroidFragment fournit également un objet fragmentState pour créer l'AndroidFragment avec un état donné, des arguments à transmettre au nouveau fragment et un rappel onUpdate qui fournit le fragment à partir de la composition. Comme de nombreux autres composables intégrés, AndroidFragment accepte un paramètre Modifier que vous pouvez utiliser, par exemple, pour définir sa position dans le composable parent.

Appelez AndroidFragment dans Compose comme suit :

@Composable
fun FragmentInComposeExample() {
    AndroidFragment<MyFragment>()
}

Appeler le framework Android à partir de Compose

Compose fonctionne dans les classes du framework Android. Par exemple, il est hébergé sur les classes de vues Android, comme Activity ou Fragment, et peut utiliser des classes du framework Android comme Context, les ressources système, Service ou encore BroadcastReceiver.

Pour en savoir plus sur les ressources système, consultez la section Ressources dans Compose.

Compositions locales

Les classes CompositionLocal permettent de transmettre des données implicitement via des fonctions modulables. Elles sont généralement accompagnées d'une valeur dans un nœud spécifique de l'arborescence de l'interface utilisateur. Cette valeur peut être utilisée par ses descendants composables sans déclarer le CompositionLocal en tant que paramètre dans la fonction modulable.

CompositionLocal permet de propager des valeurs pour les types de frameworks Android dans Compose, tels que Context, Configuration ou View, dans lesquels le code Compose est hébergé avec les éléments LocalContext, LocalConfiguration ou LocalView correspondants. Notez que les classes CompositionLocal sont précédées de Local pour une meilleure visibilité avec la saisie semi-automatique dans l'IDE.

Pour accéder à la valeur actuelle de CompositionLocal, utilisez sa propriété current. Par exemple, le code ci-dessous affiche un toast en fournissant le LocalContext.current dans la méthode Toast.makeToast.

@Composable
fun ToastGreetingButton(greeting: String) {
    val context = LocalContext.current
    Button(onClick = {
        Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show()
    }) {
        Text("Greet")
    }
}

Broadcast receivers

Pour illustrer CompositionLocal et effets secondaires, si un BroadcastReceiver doit être enregistré à partir d'une fonction modulable, utilisez LocalContext pour utiliser le contexte actuel, ainsi que rememberUpdatedState et DisposableEffect effets secondaires.

@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 */
}

Autres interactions

Si aucun utilitaire n'est défini pour l'interaction dont vous avez besoin, nous vous recommandons de suivre les consignes générales de Compose : le flux de données descend, le flux d'événements monte. Plus de détails sont disponibles dans Raisonnement dans Compose. Par exemple, ce composable lance une autre activité :

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