Temas personalizados en Flutter

- 👤 Andrés Cruz

🇺🇸 In english

Temas personalizados en Flutter

Los temas en Flutter son una de esas cosas que parecen simples… hasta que intentas adaptar tu app a una identidad visual específica. A mí me ha pasado: empiezas con ThemeData.dark() o ThemeData.light(), y cuando quieres replicar el branding real de un cliente, de pronto necesitas ajustar desde el color primario hasta los estilos de tus widgets personalizados.

En esta guía te cuento cómo crear temas personalizados en Flutter desde cero, cómo aprovechar ThemeData, ColorScheme, copyWith, ThemeExtension y hasta Material Design 3. Todo con ejemplos reales que uso en mis propias apps.

Qué es el theming en Flutter y por qué es clave para la identidad visual

El paquete Material de Google viene con dos temas incorporados: una versión clara (que es la predeterminada) y una versión oscura.

Adicionalmente Flutter trae dos sistemas de diseño listos para usar: Material (Android) y Cupertino (iOS). Ambos funcionan genial como punto de partida, pero rara vez reflejan el estilo visual real de una marca. En mi caso, suelo comenzar con Material porque ofrece más control inmediato y una API de theming muy completa.

Cuando una app necesita transmitir cierta personalidad (colores, tipografía, componentes), personalizar el tema se vuelve esencial.

Material vs Cupertino: cuándo usar cada enfoque

  • Material: ideal si quieres un look moderno, consistente, multiplataforma. Su ThemeData es muy completo.
  • Cupertino: perfecto para apps muy al estilo iOS, pero limitado en theming.

Personalmente, solo uso Cupertino puro cuando el diseño debe parecer 100% nativo de iOS. En todos los demás casos, Material me da más libertad.

Empezar con ThemeData: la base del theming en Flutter

ThemeData es el corazón del sistema de temas en Flutter. Desde aquí controlas colores, tipografía, densidad visual, componentes, formas y más.

ThemeData es el corazón del sistema de temas en Flutter. Desde aquí controlas colores, tipografía, densidad visual, componentes, formas y más.

Light y Dark Theme: primeros pasos

Un ejemplo base:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.dark(),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
Modo claro en Flutter
Dark Tema

Ajustar colores, tipografía y estilos globales con ThemeData

Podemos cambiar colors fácilmente, con ciertas propiedades claves como el siguiente, al igual que la tipográfica, aquí la mejor ayuda es el autocompletado de los editores como el de VSC con Control + Espacio:

theme: ThemeData(
 primaryColor: Colors.purple[800],
 fontFamily: 'Roboto',
),

Consejos prácticos para evitar errores comunes al modificar temas

  • No mezcles primaryColor con colorScheme.primary sin entender cómo se combinan.
  • Revisa tu app en modo claro y oscuro desde el inicio.
  • No apliques estilos “duros” en widgets… usa el tema siempre que sea posible.

Personalizar colorScheme para un branding sólido

Si quieres precisión visual y consistencia, el camino correcto es colorScheme. Aquí defines tu paleta completa: primarios, secundarios, error, superficie, fondo, outline, etc.

colorScheme: ColorScheme.fromSeed(
 seedColor: Colors.purple,
 brightness: Brightness.dark,
),

De esta forma, estamos cambiando un estilo existente y lo personalizamos a gusto.

Manejo de colorScheme en modo claro y oscuro

Define ambos siempre:

  • theme: ThemeData(colorScheme: lightScheme),
  • darkTheme: ThemeData(colorScheme: darkScheme),

Extender un tema existente con copyWith

También es posible tomar un tema existente y sobrescribir solo ciertas propiedades. Para extender un tema, puede usar el método copyWith para extenderlo y pasar sus estilos personalizados; esto mismo hacemos con la propiedad colorScheme, que tenemos una paleta de colores que podemos personalizar y para evitar colocarlos todos, usamos el copyWith para reutilizar estilos existentes.

ThemeData.dark().copyWith(
  colorScheme: ColorScheme.fromSwatch().copyWith(
    primary: Colors.purple,
    secondary: Colors.red,
  ),
);

El contenido principal de la aplicación aparece oscuro con texto claro. Sin embargo, la AppBar no es negra como el anterior experimento de tema oscuro. La AppBar es de color púrpura. El botón es rojo ya que es el color secundario:

Dark tema personalizado
Dark tema personalizado

Cómo aplicar estilos a widgets personalizados usando Theme.of(context)

Cuando construyo widgets propios, siempre hago que sus estilos dependan del tema actual. Esto evita tener componentes “duros” que no cambian con el modo oscuro, por ejemplo.

class _MyHomePageState extends State<MyHomePage> {
  // ...
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // ...
 floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: 'Increment',
        backgroundColor: Theme.of(context).primaryColor,
        foregroundColor: Theme.of(context).colorScheme.primary,
        child: const Icon(Icons.add),
      ),
    );
  }
}

Errores frecuentes al no usar Theme.of(context)

  • Widgets que no cambian en modo oscuro.
  • Botones que no combinan con el resto del tema.
  • Contrastes incorrectos.

Ejemplo práctico con un botón personalizado

class CustomButton extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   final scheme = Theme.of(context).colorScheme;
   return ElevatedButton(
     onPressed: () {},
     style: ElevatedButton.styleFrom(
       backgroundColor: scheme.primary,
       foregroundColor: scheme.onPrimary,
     ),
     child: const Text('Guardar'),
   );
 }
}

Conclusión

Crear temas personalizados en Flutter no solo consiste en cambiar colores: se trata de construir una identidad visual sólida, coherente y mantenible. Con ThemeData, colorScheme, copyWith, ThemeExtension y Material 3 tienes todas las herramientas para hacerlo de forma profesional.

En mi experiencia, el mayor salto de calidad ocurre cuando dejas de aplicar estilos directamente a los widgets y empiezas a delegar todo en el tema global.

Preguntas frecuentes sobre temas personalizados en Flutter

  • ¿Debo usar ThemeData o ThemeExtension?
    • Depende: ThemeData para lo estándar, ThemeExtension para lo que no existe.
  • ¿Puedo mezclar Material Design 2 y 3?
    • Sí, pero no es recomendable a largo plazo.
  • ¿Cómo cambio el tema entre claro y oscuro?
    • Con themeMode: ThemeMode.system o un toggler manual.

Acepto recibir anuncios de interes sobre este Blog.

Veremos como podemos cambiar el estilo de light o dark y personalizar el mismo en Flutter para usar a lo largo de toda la aplicación.

| 👤 Andrés Cruz

🇺🇸 In english