Cómo agregar Jetpack Compose a tu app

Si quieres usar Jetpack Compose en un proyecto existente, tendrás que configurar el proyecto con las opciones de configuración y las dependencias requeridas.

Cómo configurar tu entorno de desarrollo

Instala la versión correcta de Android Studio

Para obtener la mejor experiencia de desarrollo con Jetpack Compose, debes descargar Android Studio Arctic Fox y configurar el complemento de Android para Gradle correspondiente a la versión de Android Studio:

buildscript {
    ...
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.0"
        ...
    }
}

Cómo configurar Kotlin

Asegúrate de usar Kotlin 1.5.21 en tu proyecto:

plugins {
    id 'org.jetbrains.kotlin:android' version '1.5.21'
}

Cómo configurar Gradle

Tienes que establecer el nivel mínimo de API de la app en 21 o más, y habilitar Jetpack Compose en el archivo build.gradle de la app, como se muestra a continuación. También debes configurar la versión para el complemento del compilador de Kotlin.

android {
    defaultConfig {
        ...
        minSdkVersion 21
    }

    buildFeatures {
        // Enables Jetpack Compose for this module
        compose true
    }
    ...

    // Set both the Java and Kotlin compilers to target Java 8.
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }

    composeOptions {
        kotlinCompilerExtensionVersion '1.0.1'
    }
}

Cómo agregar dependencias del kit de herramientas de Jetpack Compose

Incluye las dependencias del kit de herramientas de Jetpack Compose en el archivo build.gradle de la app, como se muestra a continuación:

dependencies {
    // Integration with activities
    implementation 'androidx.activity:activity-compose:1.3.1'
    // Compose Material Design
    implementation 'androidx.compose.material:material:1.0.1'
    // Animations
    implementation 'androidx.compose.animation:animation:1.0.1'
    // Tooling support (Previews, etc.)
    implementation 'androidx.compose.ui:ui-tooling:1.0.1'
    // Integration with ViewModels
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07'
    // UI Tests
    androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.0.1'
}

Vuelve a usar el tema de View en Compose

Si acabas de agregar Compose a tu proyecto, es posible que quieras que Compose herede los temas disponibles en el sistema View, en lugar de volver a escribir tu propio tema de Material en Compose desde cero.

Si utilizas la biblioteca de MDC en tu app para Android, la biblioteca del Adaptador de temas de MDC Compose te permitirá volver a usar fácilmente el color, la tipografía y la forma de tus temas basados en View existentes en tus elementos que admiten composición. Puedes hacerlo con la API de MdcTheme.

En cambio, si usas temas XML de AppCompat, utiliza el Adaptador de temas AppCompat Compose, que contiene la API de AppCompatTheme.

Incluye la dependencia que necesites en el archivo build.gradle de la app, como se muestra a continuación:

dependencies {
    // When using a MDC theme
    implementation "com.google.android.material:compose-theme-adapter:1.0.1"

    // When using a AppCompat theme
    implementation "com.google.accompanist:accompanist-appcompat-theme:0.16.0"
}

Comienza a migrar a Compose

Imagina que queremos migrar el texto del saludo del usuario a Jetpack Compose en nuestra aplicación. Podríamos tener el siguiente contenido en un diseño XML:

<...>
    <!-- Other content -->

    <TextView
        android:id="@+id/greeting"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/margin_small"
        android:layout_marginEnd="@dimen/margin_small"
        android:gravity="center_horizontal"
        android:text="@string/greeting"
        android:textAppearance="?attr/textAppearanceHeadline5"
        ... />
</...>

Para migrarlo a Compose, podemos reemplazar el View por un ComposeView que mantenga los mismos parámetros de diseño y id:

<...>
    <!-- Other content -->

    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/greeting"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</...>

Luego, en la Activity o el Fragment que use ese diseño XML, obtendremos la ComposeView y llamaremos al método setContent para agregarle contenido de Compose:

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...

        val greeting = findViewById<ComposeView>(R.id.greeting)
        greeting.setContent {
            MdcTheme { // or AppCompatTheme
                Greeting()
            }
        }
    }
}

@Composable
private fun Greeting() {
    Text(
        text = stringResource(R.string.greeting),
        style = MaterialTheme.typography.h5,
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = dimensionResource(R.dimen.margin_small))
            .wrapContentWidth(Alignment.CenterHorizontally)
    )
}

Para obtener más información sobre ComposeView y otras API de interoperabilidad, consulta la Guía de API de interoperabilidad. Para obtener más información sobre stringResource, dimensionResource y otras API de recursos de Compose, consulta la guía de Recursos de Compose.

Prueba tu IU híbrida

Después de migrar partes de tu app a Compose, las pruebas son fundamentales para asegurarte de que no se haya dañado nada.

Cuando una actividad o un fragmento usa Compose, en lugar de ActivityScenarioRule, debes usar createAndroidComposeRule, que integra ActivityScenarioRule con un objeto ComposeTestRule que te permite probar Compose y el código de View al mismo tiempo.

class MyActivityTest {
    @Rule
    @JvmField
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test
    fun testGreeting() {
        val greeting = InstrumentationRegistry.getInstrumentation()
            .targetContext.resources.getString(R.string.greeting)

        composeTestRule.onNodeWithText(greeting).assertIsDisplayed()
    }
}

Consulta la guía sobre cómo probar tu diseño de Compose para obtener más información sobre las pruebas y la interoperabilidad con Espresso.

Compose en tu arquitectura

Compose admite la mayoría de las arquitecturas de apps y ofrece integraciones con muchas otras bibliotecas populares. Por lo tanto, no es necesario que cambies otras capas de la jerarquía para comenzar a usar Compose en tu app.

En el siguiente fragmento de código, se muestra cómo funciona Compose con los ViewModels de los componentes de la arquitectura mediante la función viewModel() y se recopila de un flujo de Kotlin con collectAsState().

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyScreen()
        }
    }
}

@Composable
private fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsState()
    when {
        uiState.isLoading -> { /* ... */ }
        uiState.isSuccess -> { /* ... */ }
        uiState.isError -> { /* ... */ }
    }
}

class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(MyScreenState.Loading)
    val uiState: StateFlow<MyScreenState> = _uiState
}

Para ver más integraciones, como la carga de imágenes, Paging o Hilt, consulta la guía sobre Compose y otras bibliotecas.

Si usas el componente Navigation de tu app, consulta la sección Interoperabilidad de la guía sobre Cómo navegar con Compose.

Próximos pasos

Puedes encontrar más información sobre Compose en el índice de documentación. Existen diferentes enfoques para implementar Compose en tu app. Obtén más información en la guía sobre cómo implementar Compose en tu app, que también contiene vínculos a otras guías, como Compose en tu arquitectura existente y Compose en tu IU existente.