Pular para conteúdo

Interoperabilidade: Usando Views no Compose

O Compose já possui suporte a muitos recursos e bibliotecas, no entanto, o ecossistema Android como um todo ainda tem dependências com o sistema de Views/XML e algumas bibliotecas ainda não oferecem suporte ao Jetpack Compose. Isso também é especialmente válido em um contexto de migração, onde um app com o sistema de Views está em processo de migração para o Compose. Como reescrever toda a base de código de uma vez muitas vezes é impensável, Compose também oferece o recurso de interoperabilidade, onde podemos tanto usar Views no Compose, quanto usar Compose em Views, o que facilita reescrever apenas as partes essenciais por etapas.

Nessa seção vamos ver uma breve introdução a esse recurso de interoperabilidade.

AndroidView

Compose possui o componente AndroidView() para utilizar Views em Composables. Vamos usar o TextView como um pequeno exemplo básico.

@Composable
private fun ComposeTextView() {
    var count by remember { mutableIntStateOf(0) }
    AndroidView(
        factory = { context ->
            // Cria e retorna a View (TextView)
            TextView(context).apply {
                // Aplica customizações iniciais
                textSize = 22f
                setTextColor(Color.Blue.toArgb())
                setOnClickListener {
                    count++
                }
            }
        },
        update = { textView ->
            // Atualiza a View de acordo com alguma mudança de estado
            textView.text = "Jetpack Compose Journey $count"
        },
        modifier = Modifier.fillMaxWidth()
    )
}

AndroidView

Temos dois parâmetros importantes:

  • factory é onde inicializamos a View a ser utilizada. O trecho de código em factory será executado exatamente uma vez e é o lugar ideal para inicializar propriedades importantes iniciais. No código acima, definimos algumas pequenas propriedades do TextView e também adicionamos um setOnClickListener(), que será acionado sempre que o TextView for tocado.
  • update será chamado múltiplas vezes e é o lugar certo para realizar atualizações de propriedades da View com base em alguma mudança de estado. Como ele é chamado múltiplas vezes nas recomposições, é importante estar atento para não realizar operações muito caras aqui.

Duas bibliotecas populares que ainda não oferecem suporte oficial ao Compose e podem ser utilizadas com AndroidView() são a Media3/ExoPlayer e AdMob.

AndroidViewBinding e Fragments no Compose

Também é possível utilizar o componente AndroidViewBinding para carregar layouts gerados pelo ViewBinding. Porém, diferente do AndroidView, é preciso adicionar a dependência abaixo e ativar o ViewBinding no build.gradle (app) (se você estiver usando XML, provavelmente já está fazendo esse último):

android {
    ...
    buildFeatures {
        compose = true
        viewBinding = true
    }
    ...

dependencies {
    ...
    implementation("androidx.compose.ui:ui-viewbinding")
    ...
}

Dessa forma podemos utilizar o layout da seguinte forma abaixo, com o exemplo retirado da documentação:

@Composable
fun AndroidViewBindingExample() {
    AndroidViewBinding(ExampleLayoutBinding::inflate) {
        exampleView.setBackgroundColor(Color.GRAY)
    }
}

E para utilizar Fragments, também utilizamos AndroidViewBinding, que tem manipulação específica de Fragment, como a remoção do Fragment quando o Composable sai da composição. Faça isso inflando um XML contendo um FragmentContainerView como suporte para o Fragment.

Por exemplo, se você tiver my_fragment_layout.xml, poderá usar um código como o abaixo ao substituir o atributo XML android:name pelo nome da classe do Fragment:

<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.example.compose.snippets.interop.MyFragment" />

E no Compose, use da seguinte forma:

@Composable
fun FragmentInComposeExample() {
    AndroidViewBinding(MyFragmentLayoutBinding::inflate) {
        val myFragment = fragmentContainerView.getFragment<MyFragment>()
        // ...
    }
}

Conclusão

Evitei exemplos mais elaborados nos tópicos de AndroidViewBinding e Fragments porque precisaria usar XML para ter algo mais prático. Como não é a intenção desse conteúdo abordar XML, achei melhor utilizar apenas os exemplos da própria documentação, pois caso você de fato precise disso, já deve estar familiarizado com XML para tal e essa pequena introdução pode ser o suficiente para saber que é possível.

Vimos apenas o uso de Views no Compose, mas como dito antes, também podemos utilizar Compose em Views. Pelos mesmos motivos citados acima, evitarei falar sobre esse tópico nessa seção e você pode ler mais sobre isso na documentação.

🔗 Conteúdos auxiliares: