Korzystanie z opcji tworzenia w widokach

Interfejs oparty na tworzeniu możesz dodać do istniejącej aplikacji, która korzysta z widoku danych.

Aby utworzyć nowy ekran, w całości oparty na interfejsie Compose, Twoja aktywność powinna wywoływać metodę setContent() i przekazywać 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!")
}

Wygląda on tak samo jak w aplikacji obsługującej tylko tworzenie wiadomości.

ViewCompositionStrategy przez ComposeView

ViewCompositionStrategy określa, kiedy należy usunąć kompozycję. Domyślnie ViewCompositionStrategy.Default usuwa kompozycję, gdy bazowy element ComposeView odłącza się od okna, chyba że jest częścią kontenera zbiorczego, np. RecyclerView. W przypadku aplikacji, która służy tylko do tworzenia wiadomości z jedną aktywnością, oczekujesz tego domyślnego działania. Jeśli jednak stopniowo dodajesz opcję tworzenia do bazy kodu, to zachowanie w niektórych sytuacjach może spowodować utratę stanu.

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

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

ViewCompositionStrategy Opis i scenariusz interakcji
DisposeOnDetachedFromWindow Kompozycja zostanie usunięta po odłączeniu bazowego elementu ComposeView od okna. Zastąpiła ją DisposeOnDetachedFromWindowOrReleasedFromPool.

Scenariusz interakcji:

* ComposeView niezależnie od tego, czy jest to jedyny element w hierarchii widoków, czy też w kontekście mieszanego ekranu widoku/tworzenia (nie w przypadku fragmentu).
DisposeOnDetachedFromWindowOrReleasedFromPool (domyślnie) Podobnie jak w przypadku DisposeOnDetachedFromWindow, gdy kompozycja nie znajduje się w kontenerze zbiorczym, takim jak RecyclerView. Jeśli kontener ten znajduje się w kontenerze puli, zostanie zniszczony, gdy sam kontener odłączy się od okna lub gdy element zostanie odrzucony (np. gdy pula jest pełna).

Scenariusz:

* ComposeView niezależnie od tego, czy jest to jedyny element w hierarchii widoków danych, czy też w kontekście mieszanego ekranu widoku/tworzenia (nie w obszarze Fragment).
* ComposeView jako element w kontenerze zbiorczym, takim jak RecyclerView.
DisposeOnLifecycleDestroyed Kompozycja zostanie zniszczona po zniszczeniu podanej Lifecycle.

Scenariusz interakcji

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

Scenariusz interakcji:

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

ComposeView we fragmentach

Jeśli chcesz uwzględnić treść interfejsu tworzenia wiadomości we fragmencie lub istniejącym układzie widoku, użyj funkcji ComposeView i wywołaj jej metodę setContent(). ComposeView to Android View.

Element ComposeView możesz umieścić w układzie XML tak 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 zwiększ układ, korzystając z zasobu układu zdefiniowanego w pliku XML. Następnie pobierz ComposeView za pomocą identyfikatora XML, ustaw strategię kompozycji, która najlepiej sprawdza się w przypadku 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óżniące się elementy tekstowe, jeden nad drugim

Rysunek 1. Pokazuje 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 Utwórz tekst.

Możesz też umieścić obiekt ComposeView bezpośrednio we fragmencie, jeśli Twój pełny ekran został utworzony za pomocą funkcji Utwórz. Pozwala to uniknąć całkowicie 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 jest wiele elementów ComposeView, każdy z nich musi mieć unikalny identyfikator, aby savedInstanceState działał.

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świetl podgląd funkcji kompozycyjnych w edytorze układu

W edytorze układu możesz też wyświetlić podgląd elementów kompozycyjnych w układzie XML zawierającym ComposeView. Dzięki temu możesz zobaczyć, jak kompozycje wyglądają w układzie mieszanym widoków i tworzenia.

Załóżmy, że chcesz wyświetlić w edytorze układów następującą funkcję kompozycyjną. Pamiętaj, że komponenty kompozycyjne z adnotacjami @Preview dobrze nadają się do wyświetlenia w edytorze układu.

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

Aby wyświetlić ten element kompozycyjny, użyj atrybutu narzędzia tools:composableName i ustaw jego wartość na pełną nazwę elementu kompozycyjnego do wyświetlenia 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>

Element kompozycyjny wyświetlany w edytorze układu

Dalsze kroki

Znasz już interfejsy API interoperacyjności, które pozwalają korzystać z funkcji tworzenia w widokach danych, więc dowiedz się, jak używać widoków danych w widoku tworzenia wiadomości.