Menggunakan Compose di View

Anda dapat menambahkan UI berbasis Compose ke dalam aplikasi yang sudah ada dan menggunakan desain berbasis View.

Untuk membuat layar baru yang sepenuhnya berbasis Compose, minta aktivitas Anda memanggil metode setContent(), dan teruskan fungsi composable mana pun yang Anda suka.

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

Kode ini terlihat seperti yang Anda temukan di aplikasi khusus Compose.

ViewCompositionStrategy untuk ComposeView

ViewCompositionStrategy menentukan kapan Komposisi harus dibuang. Secara default, ViewCompositionStrategy.Default, akan membuang Komposisi jika ComposeView yang mendasarinya terpisah dari jendela, kecuali jika Komposisi merupakan bagian dari penampung penggabungan seperti RecyclerView. Di aplikasi khusus Compose Aktivitas tunggal, perilaku default ini adalah yang Anda inginkan. Namun, jika Anda menambahkan Compose secara bertahap dalam codebase, perilaku ini dapat menyebabkan hilangnya status dalam beberapa skenario.

Untuk mengubah ViewCompositionStrategy, panggil metode setViewCompositionStrategy() dan berikan strategi yang berbeda.

Tabel di bawah ini merangkum berbagai skenario yang dapat Anda gunakan untuk ViewCompositionStrategy dalam:

ViewCompositionStrategy Deskripsi dan Skenario Interop
DisposeOnDetachedFromWindow Komposisi akan dibuang saat ComposeView dasar dilepas dari jendela. Sejak itu telah digantikan oleh DisposeOnDetachedFromWindowOrReleasedFromPool.

Skenario interop:

* ComposeView baik sebagai satu-satunya elemen dalam hierarki View, maupun dalam konteks layar View/Compose campuran (bukan dalam Fragment).
DisposeOnDetachedFromWindowOrReleasedFromPool (Default) Serupa dengan DisposeOnDetachedFromWindow, saat Komposisi tidak berada dalam penampung penggabungan, seperti RecyclerView. Jika penampung berada di container penggabungan, penampung tersebut akan dibuang saat container penggabungan sendiri terpisah dari jendela, atau saat item dibuang (yaitu saat kumpulan penuh).

Skenario interop:

* ComposeView baik sebagai satu-satunya elemen di hierarki View maupun dalam konteks layar View/Compose campuran (bukan dalam Fragment).
* ComposeView sebagai item dalam container penggabungan seperti RecyclerView.
DisposeOnLifecycleDestroyed Komposisi akan dibuang saat Lifecycle yang disediakan dihancurkan.

Skenario interop

* ComposeView dalam View Fragment.
DisposeOnViewTreeLifecycleDestroyed Komposisi akan dibuang jika Lifecycle yang dimiliki oleh LifecycleOwner yang ditampilkan oleh ViewTreeLifecycleOwner.get dari jendela berikutnya tempat View dilampirkan.

Skenario interop:

* ComposeView dalam View Fragment.
* ComposeView dalam Tampilan yang Lifecycle belum diketahui.

ComposeView di Fragmen

Jika Anda ingin menggabungkan konten UI Compose dalam fragmen atau tata letak View yang sudah ada, gunakan ComposeView dan panggil metode setContent(). ComposeView adalah View Android.

Anda dapat menempatkan ComposeView di tata letak XML, seperti View lainnya:

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

Dalam kode sumber Kotlin, inflate tata letak dari resource tata letak yang ditentukan dalam XML. Kemudian, dapatkan ComposeView menggunakan ID XML, tetapkan strategi Komposisi yang paling sesuai untuk View host, dan panggil setContent() untuk menggunakan 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
    }
}

Atau, Anda juga dapat menggunakan view binding untuk mendapatkan referensi ke ComposeView dengan mereferensikan class binding yang dihasilkan untuk file tata letak XML Anda:

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

Dua elemen teks yang sedikit berbeda, satu di atas yang lain

Gambar 1. Gambar ini menunjukkan output kode yang menambahkan elemen Compose dalam hierarki UI View. Teks "Hello Android!" ditampilkan oleh widget TextView. Teks "Hello Compose!" ditampilkan oleh elemen teks Compose.

Anda juga dapat menyertakan ComposeView secara langsung dalam fragmen jika layar penuh Anda dibuat dengan Compose, yang memungkinkan Anda menghindari penggunaan file tata letak XML sepenuhnya.

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

Beberapa instance ComposeView dalam tata letak yang sama

Jika ada beberapa elemen ComposeView dalam tata letak yang sama, masing-masing harus memiliki ID unik agar savedInstanceState dapat berfungsi.

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

ID ComposeView ditentukan dalam file res/values/ids.xml:

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

Melihat pratinjau composable di Layout Editor

Anda juga dapat melihat pratinjau composable dalam Layout Editor untuk tata letak XML yang berisi ComposeView. Dengan begitu, Anda dapat melihat tampilan composable dalam tata letak campuran View dan Compose.

Misalnya, Anda ingin menampilkan composable berikut di Layout Editor. Perhatikan bahwa composable yang dianotasi dengan @Preview adalah kandidat yang baik untuk dipratinjau di Layout Editor.

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

Untuk menampilkan composable ini, gunakan atribut alat tools:composableName dan tetapkan nilainya ke nama composable yang sepenuhnya memenuhi syarat untuk melihat pratinjau dalam tata letak.

<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 yang ditampilkan dalam layout editor

Langkah berikutnya

Setelah Anda mengetahui API interoperabilitas untuk menggunakan Compose di View, pelajari cara menggunakan View di Compose.