Utilizzare la funzionalità Scrivi in Visualizzazioni

Puoi aggiungere una UI basata su Compose a un'app esistente che utilizza un design basato sulle visualizzazioni.

Per creare una nuova schermata interamente basata sulla scrittura, fai in modo che l'attività chiami il metodo setContent() e trasmetti le funzioni componibili che preferisci.

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

Questo codice è esattamente simile a quello che puoi trovare in un'app solo per Compose.

ViewCompositionStrategy per ComposeView

ViewCompositionStrategy definisce quando la composizione deve essere smaltita. L'impostazione predefinita, ViewCompositionStrategy.Default, elimina la composizione quando l'elemento ComposeView sottostante si scollega dalla finestra, a meno che non faccia parte di un container di pooling come un RecyclerView. Questo comportamento predefinito è quello desiderato in un'app solo per Scrittura di attività. Tuttavia, se aggiungi in modo incrementale Compose al tuo codebase, questo comportamento potrebbe causare la perdita di stato in alcuni scenari.

Per modificare ViewCompositionStrategy, chiama il metodo setViewCompositionStrategy() e fornisci una strategia diversa.

La tabella seguente riassume i diversi scenari in cui puoi utilizzare ViewCompositionStrategy:

ViewCompositionStrategy Descrizione e scenario di interoperabilità
DisposeOnDetachedFromWindow La composizione verrà eliminata quando l'elemento ComposeView sottostante verrà scollegato dalla finestra. È stato poi sostituito da DisposeOnDetachedFromWindowOrReleasedFromPool.

Scenario di interazione:

* ComposeView se è l'unico elemento nella gerarchia delle viste o nel contesto di una schermata mista di tipo Vista/Scrittura (non in Fragment).
DisposeOnDetachedFromWindowOrReleasedFromPool (valore predefinito) Simile a DisposeOnDetachedFromWindow, quando la composizione non si trova in un contenitore di pooling, ad esempio un RecyclerView. Se si trova in un container di pool, viene eliminato quando il container stesso si scollega dalla finestra o quando l'elemento viene eliminato (ad esempio quando il pool è pieno).

Scenario di interazione:

* ComposeView se si tratta dell'unico elemento nella gerarchia di visualizzazione o nel contesto di una schermata mista di visualizzazione/scrittura (non in un frammento).
* ComposeView come elemento in un container di pool come RecyclerView.
DisposeOnLifecycleDestroyed La composizione verrà smaltita quando verrà eliminata la Lifecycle fornita.

Scenario dell'interazione

* ComposeView nella vista di un frammento.
DisposeOnViewTreeLifecycleDestroyed La composizione verrà eliminata quando il Lifecycle di proprietà del LifecycleOwner restituito entro il ViewTreeLifecycleOwner.get della finestra successiva a cui è associata la vista viene eliminata.

Scenario dell'interazione:

* ComposeView nella vista di un frammento.
* ComposeView in una vista in cui il ciclo di vita non è ancora noto.

ComposeView in frammenti

Se vuoi incorporare i contenuti dell'interfaccia utente di Compose in un frammento o in un layout di visualizzazione esistente, usa ComposeView e chiama il relativo metodo setContent(). ComposeView è un View Android.

Puoi inserire ComposeView nel layout XML come qualsiasi altro 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>

Nel codice sorgente Kotlin, aumenta il layout della risorsa layout definita nel file XML. Quindi recupera ComposeView utilizzando l'ID XML, imposta una strategia di composizione ottimale per l'host View e chiama setContent() per utilizzare 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
    }
}

In alternativa, puoi anche utilizzare l'associazione di visualizzazioni per ottenere riferimenti a ComposeView, facendo riferimento alla classe di associazione generata per il file di layout 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
    }
}

Due elementi di testo leggermente diversi, uno sopra l&#39;altro

Figura 1. Questo mostra l'output del codice che aggiunge elementi Compose in una gerarchia dell'UI di visualizzazione. Il testo "Ciao Android!" viene visualizzato da un widget TextView. Il testo "Hello Compose!" viene visualizzato da un elemento di testo Compose.

Puoi anche includere ComposeView direttamente in un frammento se lo schermo intero è stato creato con Compose, il che ti consente di evitare di utilizzare completamente un file di layout 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!")
                }
            }
        }
    }
}

Più istanze ComposeView nello stesso layout

Se ci sono più elementi ComposeView nello stesso layout, ognuno deve avere un ID univoco affinché savedInstanceState funzioni.

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

Gli ID ComposeView sono definiti nel file res/values/ids.xml:

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

Visualizza l'anteprima dei componibili nell'Editor layout

Puoi anche visualizzare l'anteprima dei componibili nell'Editor di layout per il layout XML che contiene un ComposeView. In questo modo potrai vedere l'aspetto dei componibili in un layout misto di Visualizzazioni e Compose.

Supponiamo che tu voglia visualizzare il seguente componibile nell'Editor layout. Tieni presente che i componibili annotati con @Preview sono ideali per l'anteprima nell'Editor di layout.

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

Per visualizzare l'elemento componibile, utilizza l'attributo strumenti tools:composableName e imposta il suo valore sul nome completo del componibile da visualizzare in anteprima nel layout.

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

Componibile visualizzato nell&#39;editor di layout

Passaggi successivi

Ora che conosci le API di interoperabilità per utilizzare Compose in Views, scopri come utilizzare Views in Compose.