Como usar o Compose em visualizações

É possível adicionar uma interface com base no Compose a um app já existente que usa um design com base em visualização.

Para criar uma tela totalmente baseada no Compose, faça sua atividade chamar o método setContent() e transmitir as funções combináveis que você quer usar.

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

Esse código é parecido com o que você encontraria em um app feito inteiramente com o Compose.

ViewCompositionStrategy por ComposeView

ViewCompositionStrategy define quando a composição deve ser descartada. O padrão, ViewCompositionStrategy.Default, descarta a composição quando o ComposeView subjacente é desanexado da janela, a menos que faça parte de um contêiner de pool, como um RecyclerView. Em um app de atividade única somente com Compose, esse comportamento padrão é o que você quer. No entanto, se você estiver adicionando o Compose de forma incremental na base de código, esse comportamento poderá causar perda de estado em alguns cenários.

Para mudar o ViewCompositionStrategy, chame o método setViewCompositionStrategy() e forneça uma estratégia diferente.

A tabela abaixo resume os diferentes cenários em que você pode usar o ViewCompositionStrategy:

ViewCompositionStrategy Descrição e cenário de interoperabilidade
DisposeOnDetachedFromWindow A composição será descartada quando o ComposeView subjacente for removido da janela. Desde então, foi substituído por DisposeOnDetachedFromWindowOrReleasedFromPool.

Cenário de interoperabilidade:

* ComposeView, seja o único elemento na hierarquia de visualização ou no contexto de uma tela mista de visualização/composição (não em fragmento).
DisposeOnDetachedFromWindowOrReleasedFromPool (padrão) Semelhante a DisposeOnDetachedFromWindow, quando a composição não está em um contêiner de pooling, como um RecyclerView. Se estiver em um contêiner de agrupamento, ele será descartado quando o contêiner for separado da janela ou quando o item for descartado (ou seja, quando o pool estiver cheio).

Cenário de interoperabilidade:

* ComposeView se é o único elemento na hierarquia de visualização ou no contexto de uma tela mista de visualização/composição (não em fragmento).
* ComposeView como um item em um contêiner de pool, como RecyclerView.
DisposeOnLifecycleDestroyed A composição será descartada quando o Lifecycle fornecido for destruído.

Cenário de interoperabilidade

* ComposeView em uma visualização de fragmento.
DisposeOnViewTreeLifecycleDestroyed A composição será descartada quando o Lifecycle pertencente ao LifecycleOwner retornado por ViewTreeLifecycleOwner.get da próxima janela a que a visualização está anexada for destruído.

Cenário de interoperabilidade:

* ComposeView em uma visualização de fragmento.
* ComposeView em uma visualização em que o ciclo de vida ainda não é conhecido.

ComposeView em fragmentos

Se você quiser incorporar o conteúdo da interface do Compose em um fragmento ou um layout de visualização já existente, use ComposeView e chame o método setContent() dele. ComposeView é uma View para Android.

Você pode colocar a ComposeView no seu layout XML como qualquer outra 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>

No código-fonte do Kotlin, infle o layout usando o recurso de layout definido no XML. Em seguida, acesse a ComposeView usando o ID do XML, defina uma estratégia de composição que funcione melhor para a View host e chame setContent() para usar o 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     } }

Como alternativa, você também pode usar a vinculação de visualizações para acessar referências ao ComposeView referenciando a classe de vinculação gerada para seu arquivo de layout 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     } }

Dois elementos de texto um pouco diferentes, um acima do outro

Figura 1. Isso mostra a saída do código que adiciona elementos do Compose a uma hierarquia de interface de visualização. A mensagem "Hello Android!" é exibida por um widget TextView. A mensagem "Hello Compose!" é exibida por um elemento de texto do Compose.

Também será possível incluir uma ComposeView diretamente em um fragmento se a tela cheia for criada com o Compose, o que permite evitar totalmente o uso de um arquivo de layout 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!")                 }             }         }     } }

Várias instâncias de ComposeView no mesmo layout

Se houver vários elementos ComposeView no mesmo layout, cada um precisará ter um ID exclusivo para que o savedInstanceState funcione.

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

Os IDs ComposeView são definidos no arquivo res/values/ids.xml:

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

Visualizar elementos combináveis no Layout Editor

Também é possível visualizar combináveis no Layout Editor para seu layout XML que contém um ComposeView. Assim, você pode ver como os elementos combináveis ficam em um layout misto de visualizações e Compose.

Suponha que você queira mostrar o seguinte elemento combinável no Layout Editor. Observação: os elementos combináveis anotados com @Preview são bons candidatos para visualização no Layout Editor.

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

Para mostrar esse elemento combinável, use o atributo de ferramentas tools:composableName e defina o valor dele como o nome totalmente qualificado do elemento combinável para prévia no layout.

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

Elemento combinável mostrado no Layout Editor

Próximas etapas

Agora que você aprendeu sobre as APIs de interoperabilidade para usar o Compose em visualizações, saiba como usar as visualizações no Compose.