Korzystanie z opcji tworzenia w widokach

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

Aby utworzyć nowy ekran oparty całkowicie na Compose, wywołaj w swojej czynności metodę setContent() i przekaż dowolne funkcje kompozytowe.

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 kod w aplikacji tylko do tworzenia wiadomości.

ViewCompositionStrategy przez ComposeView

ViewCompositionStrategyokreśla, kiedy kompozycja powinna zostać usunięta. Domyślna wartość, ViewCompositionStrategy.Default, usuwa kompozycję, gdy element podstawowy ComposeView odłącza się od okna, chyba że jest częścią kontenera z grupowaniem, takiego jak RecyclerView. W przypadku aplikacji z jedną aktywnością, która korzysta tylko z Compose, takie domyślne zachowanie jest pożądane, ale jeśli stopniowo dodajesz Compose do repozytorium kodu, w niektórych przypadkach może to spowodować utratę stanu.

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

Tabela poniżej zawiera podsumowanie różnych scenariuszy, w których możesz użyć funkcjiViewCompositionStrategy:

ViewCompositionStrategy Opis i scenariusz interoperacyjności
DisposeOnDetachedFromWindow Skład zostanie usunięty, gdy podstawowy element ComposeView zostanie odłączony od okna. Został zastąpiony przez DisposeOnDetachedFromWindowOrReleasedFromPool.

Scenariusz interoperacyjności:

* ComposeViewczy jest to jedyny element w hierarchii widoku czy w kontekście mieszanego ekranu Widok/Kompozycja (nie w Fragment).
DisposeOnDetachedFromWindowOrReleasedFromPool (wartość domyślna) Podobnie jak w przypadku DisposeOnDetachedFromWindow, gdy kompozycja nie znajduje się w kontenerze z poolingiem, np. RecyclerView. Jeśli znajduje się w kontenerze z poolingiem, zostanie usunięty, gdy sam kontener z poolingiem zostanie odłączony od okna lub gdy element zostanie odrzucony (czyli gdy pula jest pełna).

Scenariusz interoperacyjności:

* ComposeView niezależnie od tego, czy jest jedynym elementem w hierarchii widoku, czy w kontekście mieszanego ekranu widoku/tworzenia (nie w Fragment).
* ComposeView jako element w kontenerze zbiorczym, takim jak RecyclerView.
DisposeOnLifecycleDestroyed Skład zostanie usunięty, gdy podany obiekt Lifecycle zostanie usunięty.

Scenariusz interoperacyjności

* ComposeView w widoku fragmentu.
DisposeOnViewTreeLifecycleDestroyed Skład zostanie usunięty, gdy Lifecycle należący do LifecycleOwner zwracany przez ViewTreeLifecycleOwner.get następnego okna, do którego jest przyłączony widok, zostanie usunięty.

Scenariusz interoperacyjności:

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

ComposeView w Fragmentach

Jeśli chcesz uwzględnić zawartość interfejsu Compose w fragmentie lub istniejącym widoku, użyj klasy ComposeView i wywołaj jej metodę setContent(). ComposeView to urządzenie z Androidem View.

Możesz umieścić element ComposeView 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 źródłowym kodzie Kotlina napełnij układ z zasobu układu zdefiniowanego w pliku XML. Następnie pobierz ComposeView za pomocą identyfikatora XML, ustaw strategię tworzenia, która najlepiej pasuje do hosta View, i wywołaj setContent(), aby użyć 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ć widoku z powiązaniem, aby uzyskać odwołania do elementu ComposeView, odwołując się do wygenerowanej klasy powiązania w 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
    }
}

2 nieco różniące się elementy tekstowe, jeden nad drugim

Rysunek 1. Pokazuje to wynik działania kodu, który dodaje elementy Compose w hierarchii interfejsu View. Tekst „Hello Android!” wyświetla się w widżecie TextView. Tekst „Cześć, Compose” jest wyświetlany przez element tekstowy Compose.

Możesz też umieścić ComposeView bezpośrednio w fragmentach, jeśli Twój pełny ekran został utworzony za pomocą Compose. Pozwoli Ci to 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 wystąpień ComposeView w tym samym układzie

Jeśli w tym samym układzie jest 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 elementów składanych w Edytorze układu

Możesz też wyświetlić podgląd komponentów w Edytorze układu dla układu XML zawierającego ComposeView. Dzięki temu możesz zobaczyć, jak Twoje komponenty wyglądają w układzie mieszanym widoków i edytora.

Załóżmy, że chcesz wyświetlić w Edytorze układu tę kompozycję. Pamiętaj, że elementy składane oznaczone etykietą @Preview nadają się do wyświetlania podglądu w Edytorze układu.

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

Aby wyświetlić tę kompozycję, użyj atrybutu tools:composableName tools i ustaw jego wartość na pełną nazwę skompilowanej kompozycji, aby wyświetlić jej podgląd 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>

Elementy kompozytowe wyświetlane w edytorze układu

Dalsze kroki

Teraz, gdy znasz interfejsy API interoperacyjności, które umożliwiają korzystanie z Compose w widoku, dowiedz się, jak używać widoku w Compose.