Korzystanie z opcji tworzenia w widokach

Możesz dodać interfejs oparty na Compose do istniejącej aplikacji, która korzysta z projektu opartego na widokach.

Aby utworzyć nowy ekran oparty w całości na Compose, wywołaj w aktywności metodę setContent() i przekaż dowolne funkcje kompozycyjne.

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

Ten kod wygląda tak samo jak w aplikacji korzystającej tylko z Compose.

ViewCompositionStrategy przez ComposeView

ViewCompositionStrategy określa, kiedy należy usunąć kompozycję. Domyślna wartość, ViewCompositionStrategy.Default, powoduje usunięcie obiektu Composition, gdy powiązany z nim obiekt ComposeView zostanie odłączony od okna, chyba że jest częścią kontenera puli, takiego jak RecyclerView. W aplikacji z jednym komponentem Activity, która korzysta tylko z Compose, to domyślne zachowanie jest pożądane. Jeśli jednak stopniowo dodajesz Compose do bazy kodu, w niektórych przypadkach może to powodować utratę stanu.

Aby zmienić ViewCompositionStrategy, wywołaj metodę setViewCompositionStrategy() i podaj inną strategię.

W tabeli poniżej znajdziesz podsumowanie różnych scenariuszy, w których możesz używać funkcji ViewCompositionStrategy:

ViewCompositionStrategy Opis i scenariusz interoperacyjności
DisposeOnDetachedFromWindow Kompozycja zostanie usunięta, gdy bazowy element ComposeView zostanie odłączony od okna. Został zastąpiony przez DisposeOnDetachedFromWindowOrReleasedFromPool.

Scenariusz interoperacyjności:

* ComposeView czy jest to jedyny element w hierarchii widoków, czy występuje w kontekście ekranu mieszanego (widok/Compose) (nie w fragmencie).
DisposeOnDetachedFromWindowOrReleasedFromPool (domyślna) Podobnie jak w przypadku DisposeOnDetachedFromWindow, gdy kompozycja nie znajduje się w kontenerze puli, np. w RecyclerView. Jeśli znajduje się w kontenerze puli, zostanie usunięty, gdy kontener puli zostanie odłączony od okna lub gdy element zostanie odrzucony (czyli gdy pula będzie pełna).

Scenariusz interoperacyjności:

* ComposeView czy jest to jedyny element w hierarchii widoków, czy znajduje się w kontekście ekranu mieszanego (widok/Compose) (nie w fragmencie).
* ComposeView jako element w kontenerze puli, np. RecyclerView.
DisposeOnLifecycleDestroyed Kompozycja zostanie usunięta, gdy podany element Lifecycle zostanie zniszczony.

Scenariusz interoperacyjności

* ComposeView w widoku fragmentu.
DisposeOnViewTreeLifecycleDestroyed Kompozycja zostanie usunięta, gdy Lifecycle należący do LifecycleOwner zwróconego przez ViewTreeLifecycleOwner.get następnego okna, do którego dołączony jest widok, zostanie zniszczony.

Scenariusz interoperacyjny:

* ComposeView w widoku fragmentu.
* ComposeView w obiekcie View, w którym cykl życia nie jest jeszcze znany.

ComposeView w sekcji Fragmenty

Jeśli chcesz włączyć treści interfejsu Compose w fragmencie lub istniejącym układzie View, użyj ComposeView i wywołaj jego metodę setContent(). ComposeView to Android View.

Element ComposeView możesz umieścić w układzie XML tak samo jak każdy inny element 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>

W kodzie źródłowym Kotlin rozwiń układ z zasobu układu zdefiniowanego w XML. Następnie pobierz ComposeView za pomocą identyfikatora XML, ustaw strategię kompozycji, która najlepiej pasuje do hosta View, i wywołaj setContent(), aby użyć funkcji 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
    }
}

Możesz też użyć powiązania widoku, aby uzyskać odwołania do ComposeView, odwołując się do wygenerowanej klasy powiązania dla pliku układu 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
    }
}

Dwa nieco różne elementy tekstowe, jeden nad drugim

Rysunek 1. Wyświetla dane wyjściowe kodu, który dodaje elementy Compose w hierarchii interfejsu View. Tekst „Hello Android!” jest wyświetlany przez widżet TextView. Tekst „Hello Compose!” jest wyświetlany przez element tekstowy Compose.

Możesz też umieścić ComposeView bezpośrednio we fragmencie, jeśli pełny ekran jest zbudowany za pomocą Compose, co pozwala całkowicie uniknąć używania pliku układu 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!")
                }
            }
        }
    }
}

Wiele instancji ComposeView w tym samym układzie

Jeśli w tym samym układzie występuje kilka elementów ComposeView, każdy z nich musi mieć unikalny identyfikator, aby element savedInstanceState działał prawidłowo.

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

Identyfikatory ComposeView są zdefiniowane w pliku res/values/ids.xml:

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

Wyświetlanie podglądu komponentów w Edytorze układu

Komponenty możesz też wyświetlać w Edytorze układu w przypadku układu XML zawierającego element ComposeView. Dzięki temu możesz zobaczyć, jak komponenty kompozycyjne wyglądają w układzie mieszanym, który zawiera widoki i kompozycje.

Załóżmy, że chcesz wyświetlić w Edytorze układu ten komponent: Uwaga: funkcje kompozycyjne oznaczone adnotacją @Preview są dobrymi kandydatami do podglądu w edytorze układu.

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

Aby wyświetlić ten komponent, użyj atrybutu tools:composableName tools i ustaw jego wartość na w pełni kwalifikowaną nazwę komponentu, który ma być wyświetlany w układzie.

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

Kompozycja wyświetlana w edytorze układu

Dalsze kroki

Teraz, gdy znasz już interfejsy API interoperacyjności, które umożliwiają używanie Compose w widokach, dowiedz się, jak używać widoków w Compose.