Utilizzare la funzionalità Scrivi in Visualizzazioni

Puoi aggiungere un'interfaccia utente basata su Compose a un'app esistente che utilizza un design basato su View.

Per creare una nuova schermata interamente basata su Compose, fai in modo che la tua attività chiami il metodo setContent() e trasmetta le funzioni composable 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 è proprio come si trova in un'app di sola scrittura.

ViewCompositionStrategy per ComposeView

ViewCompositionStrategy definisce quando la composizione deve essere eliminata. Il valore predefinito, ViewCompositionStrategy.Default, rimuove la composizione quando la ComposeView sottostante si scollegano dalla finestra, a meno che non facciano parte di un contenitore per il pooling come un RecyclerView. In un'app di sola scrittura di attività, questo comportamento predefinito è cosa vorresti, tuttavia, se aggiungi in modo incrementale Compose nella questo comportamento può causare la perdita di stato in alcuni scenari.

Per modificare ViewCompositionStrategy, chiama setViewCompositionStrategy() e fornire una strategia diversa.

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

ViewCompositionStrategy Descrizione e scenario di interoperabilità
DisposeOnDetachedFromWindow La composizione verrà eliminata quando l'elemento ComposeView sottostante viene scollegato dalla finestra. ed è stata sostituita da DisposeOnDetachedFromWindowOrReleasedFromPool.

Scenario Interop:

* ComposeView se è l'unico elemento nella gerarchia di visualizzazione o nel contesto di una schermata di tipo Visualizza/Scrivi (non in Frammento).
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 pooling, verrà eliminato quando il container di pooling si scollega dalla finestra o quando l'elemento viene eliminato (ad es. quando il pool è pieno).

Scenario Interop:

* ComposeView se è l'unico elemento nella gerarchia di visualizzazione o nel contesto di una schermata di tipo Visualizza/Scrivi (non in Frammento).
* ComposeView come elemento in un contenitore di pooling come RecyclerView.
DisposeOnLifecycleDestroyed La composizione verrà eliminata quando l'oggetto Lifecycle fornito verrà distrutto.

Scenario di interoperabilità

* ComposeView nella visualizzazione di un frammento.
DisposeOnViewTreeLifecycleDestroyed La composizione verrà eliminata quando l'elemento Lifecycle di proprietà di LifecycleOwner restituito da ViewTreeLifecycleOwner.get della finestra successiva a cui è collegata la vista viene distrutto.

Scenario Interop:

* ComposeView in una Vista frammento.
* ComposeView in una visualizzazione 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 una vista esistente utilizza ComposeView e chiamare la sua setContent() . ComposeView è una View per Android.

Puoi inserire ComposeView nel tuo 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, gonfia il layout dalla risorsa definita in XML. Quindi, recupera ComposeView utilizzando l'ID XML, imposta una strategia di composizione più adatta all'View host 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 il binding delle visualizzazioni per ottenere riferimenti a ComposeView facendo riferimento alla classe di binding 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. Mostra l'output del codice che aggiunge gli elementi Compose in un Visualizza la gerarchia dell'interfaccia utente. L'avviso "Hello Android!" viene visualizzato da un Widget TextView. Il prompt "Hello Compose!" viene visualizzato da un Componi elemento di testo.

Puoi anche includere un ComposeView direttamente in un frammento se la schermata completa è stata creata 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 nello stesso layout sono presenti più elementi ComposeView, ognuno deve dispongono di un ID univoco per il funzionamento di savedInstanceState.

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>

Visualizzare l'anteprima dei componibili nell'Editor layout

Puoi anche visualizzare l'anteprima dei composabili nell'editor di layout per il layout XML contenente un ComposeView. In questo modo puoi vedere l'aspetto dei tuoi composabili in un layout misto di Visualizzazioni e Compose.

Supponiamo che tu voglia visualizzare il seguente composable nell'editor di layout. Tieni presente che i composabili annotati con @Preview sono buoni candidati per l'anteprima nell'Editor di layout.

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

Per visualizzare questo composable, utilizza l'attributo tools:composableName tools e imposta il relativo valore sul nome completo del composable 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>

Componente componibile visualizzato nell&#39;editor di layout

Passaggi successivi

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