Utiliser Compose dans les vues

Vous pouvez ajouter une UI basée sur Compose à une application existante qui utilise un design basé sur les vues.

Pour créer un écran entièrement basé sur Compose, demandez à votre activité d'appeler la méthode setContent() et de transmettre toutes les fonctions modulables de votre choix.

class ExampleActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent { // In here, we can call composables!
            MaterialTheme {
                Greeting(name = "compose")
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

Ce code ressemble à ce que vous trouveriez dans une application Compose.

ViewCompositionStrategy pour ComposeView

ViewCompositionStrategy définit le moment où la composition doit être supprimée. La valeur par défaut, ViewCompositionStrategy.Default, supprime la composition lorsque l'élément ComposeView sous-jacent se détache de la fenêtre, sauf s'il fait partie d'un conteneur de mise en commun tel qu'un RecyclerView. Dans une application Compose à activité unique, ce comportement par défaut est ce que vous souhaitez. Toutefois, si vous ajoutez progressivement Compose dans votre codebase, ce comportement peut entraîner une perte d'état dans certains scénarios.

Pour modifier ViewCompositionStrategy, appelez la méthode setViewCompositionStrategy() et fournissez une autre stratégie.

Le tableau ci-dessous récapitule les différents scénarios dans lesquels vous pouvez utiliser ViewCompositionStrategy:

ViewCompositionStrategy Description et scénario d'interopérabilité
DisposeOnDetachedFromWindow La composition sera supprimée lorsque l'ComposeView sous-jacente sera dissociée de la fenêtre. A été remplacé par DisposeOnDetachedFromWindowOrReleasedFromPool.

Scénario d'interopérabilité:

* ComposeView qu'il s'agisse du seul élément de la hiérarchie des vues ou dans le contexte d'un écran View/Compose mixte (pas dans le fragment).
DisposeOnDetachedFromWindowOrReleasedFromPool (valeur par défaut) Comme pour DisposeOnDetachedFromWindow, lorsque la composition ne se trouve pas dans un conteneur de mise en pool, tel qu'un RecyclerView. S'il se trouve dans un conteneur de mise en commun, il sera supprimé lorsque le conteneur de mise en commun lui-même se détachera de la fenêtre ou lorsque l'élément sera supprimé (c'est-à-dire lorsque le pool sera plein).

Scénario d'interopérabilité:

* ComposeView s'il s'agit du seul élément de la hiérarchie View ou dans le contexte d'un écran View/Compose mixte (pas dans Fragment).
* ComposeView en tant qu'élément dans un conteneur de mise en commun tel que RecyclerView.
DisposeOnLifecycleDestroyed La composition sera supprimée lorsque l'Lifecycle fournie sera détruite.

Scénario d'interopérabilité

* ComposeView dans la vue d'un fragment.
DisposeOnViewTreeLifecycleDestroyed La composition sera supprimée lorsque le Lifecycle appartenant au LifecycleOwner renvoyé par ViewTreeLifecycleOwner.get de la fenêtre suivante à laquelle la vue est associée sera détruit.

Scénario d'interopérabilité:

* ComposeView dans la vue d'un fragment.
* ComposeView dans une vue dont le cycle de vie n'est pas encore connu.

ComposeView dans les fragments

Si vous souhaitez intégrer le contenu de l'interface utilisateur Compose dans un fragment ou une mise en page "View" existante, utilisez ComposeView et appelez sa méthode setContent(). ComposeView est une View Android.

Vous pouvez placer la ComposeView dans votre mise en page XML comme n'importe quelle autre View :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <TextView
      android:id="@+id/text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" />

  <androidx.compose.ui.platform.ComposeView
      android:id="@+id/compose_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />
</LinearLayout>

Dans le code source en Kotlin, gonflez la mise en page à partir de la ressource de mise en page définie en XML. Obtenez ensuite ComposeView à l'aide de l'ID XML, définissez la stratégie de composition la plus adaptée pour l'hôte View, puis appelez setContent() pour utiliser Compose.

class ExampleFragmentXml : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val view = inflater.inflate(R.layout.fragment_example, container, false)
        val composeView = view.findViewById<ComposeView>(R.id.compose_view)
        composeView.apply {
            // Dispose of the Composition when the view's LifecycleOwner
            // is destroyed
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                // In Compose world
                MaterialTheme {
                    Text("Hello Compose!")
                }
            }
        }
        return view
    }
}

Vous pouvez également utiliser la liaison de vue pour obtenir des références à ComposeView en référençant la classe de liaison générée pour votre fichier de mise en page XML:

class ExampleFragment : Fragment() {

    private var _binding: FragmentExampleBinding? = null

    // This property is only valid between onCreateView and onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentExampleBinding.inflate(inflater, container, false)
        val view = binding.root
        binding.composeView.apply {
            // Dispose of the Composition when the view's LifecycleOwner
            // is destroyed
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                // In Compose world
                MaterialTheme {
                    Text("Hello Compose!")
                }
            }
        }
        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

Deux éléments textuels légèrement différents, l&#39;un au-dessus de l&#39;autre.

Figure 1 : Cette image montre la sortie du code qui ajoute des éléments Compose dans une hiérarchie d'UI. Un widget TextView affiche le message texte "Hello Android!". Un élément de texte Compose affiche le texte "Hello Compose!".

Vous pouvez également inclure une ComposeView directement dans un fragment si votre mode plein écran est conçu avec Compose, ce qui vous évite d'utiliser un fichier de mise en page XML.

class ExampleFragmentNoXml : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return ComposeView(requireContext()).apply {
            // Dispose of the Composition when the view's LifecycleOwner
            // is destroyed
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                MaterialTheme {
                    // In Compose world
                    Text("Hello Compose!")
                }
            }
        }
    }
}

Plusieurs instances ComposeView dans la même mise en page

S'il existe plusieurs éléments ComposeView dans la même mise en page, chacun doit disposer d'un ID unique pour que savedInstanceState fonctionne correctement.

class ExampleFragmentMultipleComposeView : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View = LinearLayout(requireContext()).apply {
        addView(
            ComposeView(requireContext()).apply {
                setViewCompositionStrategy(
                    ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
                )
                id = R.id.compose_view_x
                // ...
            }
        )
        addView(TextView(requireContext()))
        addView(
            ComposeView(requireContext()).apply {
                setViewCompositionStrategy(
                    ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
                )
                id = R.id.compose_view_y
                // ...
            }
        )
    }
}

Les ID ComposeView sont définis dans le fichier res/values/ids.xml :

<resources>
  <item name="compose_view_x" type="id" />
  <item name="compose_view_y" type="id" />
</resources>

Prévisualiser les composables dans l'éditeur de mise en page

Vous pouvez également prévisualiser les composables dans l'éditeur de mise en page pour votre mise en page XML contenant un ComposeView. Vous pouvez ainsi voir à quoi ressemblent vos composables dans une mise en page mixte de vues et de Compose.

Supposons que vous souhaitiez afficher le composable suivant dans l'éditeur de mise en page. Notez que les composables annotés avec @Preview sont de bons candidats pour un aperçu dans l'éditeur de mise en page.

@Preview
@Composable
fun GreetingPreview() {
    Greeting(name = "Android")
}

Pour afficher ce composable, utilisez l'attribut d'outils tools:composableName et définissez sa valeur sur le nom complet du composable à prévisualiser dans la mise en page.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <androidx.compose.ui.platform.ComposeView
      android:id="@+id/my_compose_view"
      tools:composableName="com.example.compose.snippets.interop.InteroperabilityAPIsSnippetsKt.GreetingPreview"
      android:layout_height="match_parent"
      android:layout_width="match_parent"/>

</LinearLayout>

Composable affiché dans l&#39;éditeur de mise en page

Étapes suivantes

Maintenant que vous connaissez les API d'interopérabilité pour utiliser Compose dans les vues, découvrez comment utiliser les vues dans Compose.