Error al cambiar el color blanco en la barra de navegación de Android en React Native

Error al cambiar el color blanco en la barra de navegación de Android en React Native

Hace unas semanas, despues de algunas actualizaciones en RN (v0.79.7), me encontré con un comportamiento inesperado en Deeditt y la barra de navegación. Aunque había definido correctamente el color personalizado para la barra (la parte inferior donde están los botones del sistema en Android), en una de las vistas esa barra se volvía blanca sin razón aparente.

Lo más curioso era que el problema solo ocurría en una pantalla específica, una en la que también estaba usando KeyboardProvider (de la librería react-native-keyboard-controller) y navegación por pestañas con @react-navigation/bottom-tabs.

Después de investigar bastante, encontré que este es un fallo común en Android con React Native y que requiere una solución dividida entre código nativo y React.

Los Síntomas

  • La app inicia mostrando correctamente el color personalizado
  • Al navegar a una vista específica, la barra se pone blanca
  • Incluso al volver atrás, el color sigue en blanco
  • El color blanco persiste entre sesiones
  • Solo afecta a Android

El Diagnóstico

El problema aunque no estoy totalmente seguro, creo que se debe a una combinación de tres factores:

1. Diferencia entre configuración estática y dinámica

Normalmente, el color de la barra se define en styles.xml así:

<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
    <item name="android:navigationBarColor">@color/purple</item>
    <item name="android:windowLightNavigationBar">false</item>
</style>

Esta definición se aplica solo en el arranque de la app. Luego, otros eventos (como cambios de pantalla, apertura del teclado o librerías externas) pueden sobrescribir ese valor.

2. KeyboardProvider toma el control de la barra

La librería react-native-keyboard-controller puede tomar el control tanto del statusBar (arriba) como del navigationBar (abajo) cuando se usa con la prop statusBarTranslucent. Y si no especificamos lo contrario, puede restablecer la barra inferior al color blanco por defecto.

Ejemplo que causa el problema:

<KeyboardProvider statusBarTranslucent>
  <KeyboardAvoidingView>
    {/* contenido */}
  </KeyboardAvoidingView>
</KeyboardProvider>

3. Ciclo de vida de Android limitado para React Navigation

Los métodos típicos de actividad en Android (onCreate, onStart, onResume) no se ejecutan cuando haces una navegación de pantalla o tab dentro de React Native. Por lo tanto, no puedes confiar solo en esos métodos para mantener el color de la barra de navegación.

Como lo Solucioné

Hay que hacer dos cosas:

  1. En código nativo, volver a aplicar el color manualmente cuando sea necesario

  2. En código React Native, evitar que KeyboardProvider modifique la barra inferior

Parte 1 – Código nativo: MainActivity.kt

Aquí dejo el código con comentarios detallados para entender qué hace cada sección:

class MainActivity : ReactActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // Aplica el tema personalizado antes de mostrar la vista principal
        setTheme(R.style.AppTheme)

        // Establece una pantalla de arranque (opcional)
        setContentView(R.layout.launch_screen)

        super.onCreate(savedInstanceState)

        // Inicializa el splash screen personalizado
        RNBootSplash.init(this, R.style.BootTheme)

        // Establece manualmente el color de la barra de navegación
        setNavigationBarColor()
    }

    override fun onStart() {
        super.onStart()
        // Al volver a primer plano, reestablece el color
        setNavigationBarColor()
    }

    override fun onResume() {
        super.onResume()
        // Por seguridad, vuelve a aplicar el color al reanudar
        setNavigationBarColor()
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)

        // Este evento se lanza al cambiar de pantalla dentro de la app
        if (hasFocus) {
            setNavigationBarColor()
        }
    }

    /**
     * Aplica el color (púrpura en mi caso) a la barra inferior de navegación
     */
    private fun setNavigationBarColor() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            // Cambia el color de fondo de la barra
            window.navigationBarColor = ContextCompat.getColor(this, R.color.purple)

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                // Asegura que los iconos sean claros (blancos) en fondo oscuro
                var flags = window.decorView.systemUiVisibility
                flags = flags and android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
                window.decorView.systemUiVisibility = flags
            }
        }
    }
}

Parte 2 – React Native: corrije el uso de KeyboardProvider

Si en tus pantallas usas KeyboardProvider, asegúrate de agregar navigationBarTranslucent junto a statusBarTranslucent, esto es algo que encontré que comunmente se menciona en los comentarios de otros devs, pero definitivamente para mi no fue suficiente:

Código que causa el error

<KeyboardProvider statusBarTranslucent>

Código corregido

<KeyboardProvider statusBarTranslucent navigationBarTranslucent>

¿Por qué esto lo soluciona?

Al incluir navigationBarTranslucent, le estás diciendo a KeyboardProvider que no controle la barra inferior, y así deja intacto el color establecido desde el código nativo.

Verificaciones adicionales

Asegúrate de definir los colores

Desde el projecto de Android, en la carpta de resources/values, ubica el archivo colors.xml:

<resources>
    <color name="purple">#6C4DDA</color>
</resources>

y en la misma carpeta esta el archivo styles.xml:

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
        <item name="android:statusBarColor">@color/purple</item>
        <item name="android:navigationBarColor">@color/purple</item>
        <item name="android:windowLightNavigationBar">false</item>
    </style>
</resources>

Cómo probar si todo funciona

Después de los cambios, haz una build limpia:

cd android && ./gradlew clean && cd ..
npx react-native run-android

Y prueba:

  1. Lanzar la app → barra púrpura
  2. Navegar entre pantallas → color se mantiene
  3. Abrir teclado en formularios → color no cambia
  4. Cambiar de pestañas → sin flashes blancos
  5. Minimizar y restaurar la app → color persiste

Algunas Consideraciones adicionales

Compatibilidad con modo oscuro

Puedes adaptar el método setNavigationBarColor() para que use un color distinto en modo oscuro:

val isDarkMode = resources.configuration.uiMode and
    Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES

val colorRes = if (isDarkMode) R.color.dark_purple else R.color.purple
window.navigationBarColor = ContextCompat.getColor(this, colorRes)

Problemas en dispositivos Samsung

Algunos dispositivos Samsung ignoran los colores por defecto. Agrega esto a android/gradle.properties:

android.enforceNavigationBarContrast=false

Conclusión

Este es uno de esos bugs difíciles de identificar porque parece aleatorio, pero tiene una causa específica, esta vez me ha tomado un par de días identiicarlo, pero finalmente encontré la solución.

En mi caso, el problema solo se presentaba en una pantalla específica, y eso me ayudó a identificar la razón, aunque inicialmente no fuese tan obio que la razón era que usaba KeyboardProvider.

Al final solo bastó con agregar la prop navigationBarTranslucent y reforzar el color desde el código nativo para solucionarlo.

Happy coding! :)


Photo by Srinivasan on Unsplash

Written with StackEdit.

Jack Fiallos

Jack Fiallos

Te gustó este artículo?