Вы можете добавить пользовательский интерфейс на основе Compose в существующее приложение, использующее дизайн на основе представления.
Чтобы создать новый экран, полностью основанный на Compose, ваша активность вызывает метод setContent()
и передает любые компонуемые функции, которые вам нравятся.
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!") }
Этот код выглядит так же, как в приложении, предназначенном только для создания сообщений.
ViewCompositionStrategy
для ComposeView
ViewCompositionStrategy
определяет, когда композиция должна быть удалена. По умолчанию ViewCompositionStrategy.Default
удаляет композицию, когда базовый ComposeView
отделяется от окна, если только он не является частью контейнера объединения, такого как RecyclerView
. В приложении только с одним действием Compose такое поведение по умолчанию — это то, что вам нужно, однако если вы постепенно добавляете Compose в свою кодовую базу, это поведение может привести к потере состояния в некоторых сценариях.
Чтобы изменить ViewCompositionStrategy
, вызовите метод setViewCompositionStrategy()
и укажите другую стратегию.
В таблице ниже приведены различные сценарии, в которых можно использовать ViewCompositionStrategy
:
ViewCompositionStrategy | Описание и сценарий взаимодействия |
---|---|
DisposeOnDetachedFromWindow | Композиция будет удалена, когда базовый ComposeView будет отсоединен от окна. С тех пор был заменен DisposeOnDetachedFromWindowOrReleasedFromPool .Сценарий взаимодействия: * ComposeView , является ли он единственным элементом в иерархии представления или в контексте смешанного экрана просмотра/составления (не во фрагменте). |
DisposeOnDetachedFromWindowOrReleasedFromPool ( по умолчанию ) | Аналогично DisposeOnDetachedFromWindow , когда композиция не находится в контейнере пула, таком как RecyclerView . Если он находится в контейнере-пуле, он будет удален, когда сам контейнер-пул отсоединяется от окна или когда элемент выбрасывается (т. е. когда пул заполнен).Сценарий взаимодействия: * ComposeView , является ли он единственным элементом в иерархии представления или в контексте смешанного экрана просмотра/составления (не во фрагменте).* ComposeView как элемент в контейнере пула, таком как RecyclerView . |
DisposeOnLifecycleDestroyed | Композиция будет удалена, когда предоставленный Lifecycle будет уничтожен.Сценарий взаимодействия * ComposeView в представлении фрагмента. |
DisposeOnViewTreeLifecycleDestroyed | Композиция будет удалена, когда Lifecycle , принадлежащий LifecycleOwner , возвращенный ViewTreeLifecycleOwner.get следующего окна, к которому прикреплено представление, будет уничтожен.Сценарий взаимодействия: * ComposeView в представлении фрагмента.* ComposeView в представлении, жизненный цикл которого еще не известен. |
ComposeView
во фрагментах
Если вы хотите включить содержимое пользовательского интерфейса Compose во фрагмент или существующий макет представления, используйте ComposeView
и вызовите его метод setContent()
. ComposeView
— это View
Android.
Вы можете поместить ComposeView
в свой XML-макет так же, как и любое другое 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>
В исходном коде Kotlin разверните макет из ресурса макета , определенного в XML. Затем получите ComposeView
используя идентификатор XML, установите стратегию композиции, которая лучше всего подходит для хоста View
, и вызовите setContent()
чтобы использовать 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 } }
Альтернативно вы также можете использовать привязку представления для получения ссылок на ComposeView
ссылаясь на сгенерированный класс привязки для вашего 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 } }
Рисунок 1. Здесь показаны выходные данные кода, который добавляет элементы Compose в иерархию пользовательского интерфейса View. «Привет, Android!» текст отображается виджетом TextView
. «Привет, напишите!» текст отображается с помощью элемента «Создать текст».
Вы также можете включить ComposeView
непосредственно во фрагмент, если ваш полноэкранный режим создан с помощью Compose, что позволяет полностью избежать использования файла макета 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!") } } } } }
Несколько экземпляров ComposeView
в одном макете
Если в одном макете имеется несколько элементов ComposeView
, каждый из них должен иметь уникальный идентификатор, чтобы 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 // ... } ) } }
Идентификаторы ComposeView
определены в файле res/values/ids.xml
:
<resources> <item name="compose_view_x" type="id" /> <item name="compose_view_y" type="id" /> </resources>
Предварительный просмотр составных элементов в редакторе макетов
Вы также можете просмотреть составные элементы в редакторе макетов для вашего XML-макета, содержащего ComposeView
. Это позволит вам увидеть, как ваши составные элементы выглядят в смешанном макете Views и Compose.
Допустим, вы хотите отобразить следующий составной элемент в редакторе макетов. Обратите внимание, что составные объекты, помеченные @Preview
являются хорошими кандидатами для предварительного просмотра в редакторе макетов.
@Preview @Composable fun GreetingPreview() { Greeting(name = "Android") }
Чтобы отобразить этот составной объект, используйте атрибут инструментов tools:composableName
и установите его значение в полное имя составного объекта для предварительного просмотра в макете.
<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>
Следующие шаги
Теперь, когда вы знаете API-интерфейсы совместимости для использования Compose в представлениях, узнайте, как использовать представления в Compose .
{% дословно %}Рекомендуется для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Другие соображения
- Стратегия миграции {:#migration-strategy}
- Сравните производительность Compose и View