diegoRodicio

View Categories

🎨 Temas e estilos compartidos

🎨 Crear e aplicar un tema

Un tema define o aspecto xeral da aplicación: as cores, as fontes e os estilos que compartirán os widgets. Así, podemos manter unha aparencia común sen configurar cada botón ou texto por separado.

Para utilizalo, primeiro creamos o tema e despois aplicámolo á aplicación.

🖌️ Crear o tema

En Flutter, creamos os temas con ThemeData. Este exemplo crea un tema a partir dunha cor azul. Colócao despois dos imports, fóra das clases:

final temaCentro = ThemeData(
  colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.blue, // Cor de partida para xerar a combinación.
  ),
);

Neste código:

  • ThemeData reúne a configuración visual do tema. Podemos indicar só o que queremos personalizar; o resto conserva os valores predeterminados.
  • colorScheme contén a combinación de cores da aplicación: fondos, textos, botóns…
  • ColorScheme.fromSeed xera esa combinación a partir da cor indicada en seedColor.

💡 A cor de partida serve para obter varias cores relacionadas. Non significa que todo vaia ser azul.

📲 Aplicar o tema

Dentro do MaterialApp, engade theme: temaCentro:

MaterialApp(
  theme: temaCentro, // Aplicamos o tema que creamos.
  home: const PantallaCentro(), // Widget coa pantalla inicial da aplicación.
)

PantallaCentro representa o widget que uses como pantalla inicial.

A partir dese momento, os compoñentes Material, como FilledButton ou Card, empregan os estilos do tema automaticamente, salvo que lles indiquemos outros.

💡 Para probar outra combinación, cambia Colors.blue por Colors.green. Non necesitas cambiar a cor de cada widget.

🧪 Exemplo de aplicación do tema

🔗 DartPad:

Aplicar un tema azul á aplicación
Aplicar un tema azul á aplicación

🖌️ Usar os estilos do tema

Moitos widgets, como Card ou FilledButton, empregan automaticamente o tema da aplicación. Pero tamén podemos consultar as súas cores e estilos para aplicalos a un texto, unha icona ou un fondo.

Para acceder ao tema, escribimos esta liña dentro do método build da pantalla, antes do return:

final tema = Theme.of(context); // Consultamos o tema que recibe esta pantalla.

Theme.of(context) busca o tema que lle corresponde ao widget segundo o lugar que ocupa na aplicación. Gardámolo na variable tema para consultar as súas propiedades facilmente:

ExpresiónQue proporciona?
tema.colorScheme.primaryCor principal, útil para destacar elementos.
tema.colorScheme.surfaceCor de fondo para superficies, como paneis ou tarxetas.
tema.colorScheme.onSurfaceCor de texto ou iconas pensada para verse sobre surface.
tema.textTheme.titleLargeEstilo para un título grande.
tema.textTheme.bodyMediumEstilo para o texto habitual.

🧪 Aplicar os estilos a unha pantalla

Para probalo no programa anterior, substitúe todo o valor de home: Scaffold(...) por home: const PantallaCentro(). Despois engade a seguinte clase fóra de main. Así, a pantalla ten o seu propio build, desde o que pode consultar o tema.

Neste exemplo usamos un estilo de título e a cor principal do tema:

class PantallaCentro extends StatelessWidget {
  const PantallaCentro({super.key});

  @override
  Widget build(BuildContext context) {
    final tema = Theme.of(context); // Accedemos ao tema da aplicación.

    return Scaffold(
      appBar: AppBar(title: const Text('IES San Mamede')),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Icon(
              Icons.school,
              color: tema.colorScheme.primary, // Cor destacada do tema.
              size: 48,
            ),
            const SizedBox(height: 8),
            Text(
              '2º DAM',
              style: tema.textTheme.titleLarge, // Estilo de título do tema.
            ),
          ],
        ),
      ),
    );
  }
}

💡 Así, se cambiamos o tema, estes widgets adaptaranse ás súas cores e estilos, sen ter que modificar o código de cada un.

Usar as cores e os estilos de texto do tema
Usar as cores e os estilos de texto do tema

📍 Onde consultamos o tema?

A pantalla debe estar dentro do MaterialApp que define o tema, por exemplo, como o seu home.

Theme.of(context) busca o tema cara arriba na árbore de widgets. Por iso, o context do método que crea o propio MaterialApp non permite acceder ao tema definido dentro del.

Para facelo sinxelo, separamos as responsabilidades: a aplicación configura o tema en MaterialApp e PantallaCentro consúltao no seu build, como no exemplo anterior.

✏️ Crear unha variante con copyWith

O método copyWith permite crear unha copia dun obxecto cambiando só algunhas das súas propiedades. As propiedades que non indiquemos conservan o seu valor orixinal.

Pode empregarse, por exemplo, con ThemeData, TextTheme ou TextStyle.

Neste exemplo partimos dun estilo de texto e creamos outro aumentando o tamaño e poñéndoo en negra:

// Estilo de partida que queremos conservar.
const estiloBase = TextStyle(
  fontSize: 16,
  color: Colors.blue,
);

// Creamos outro estilo a partir do anterior.
final estiloTitulo = estiloBase.copyWith(
  fontSize: 24,
  fontWeight: FontWeight.bold,
);

estiloTitulo conserva a cor azul de estiloBase, pero cambia o tamaño e o grosor da fonte. estiloBase non se modifica.

Podemos aplicar o novo estilo a un texto:

Text(
  '2º DAM',
  style: estiloTitulo, // Aplicamos o estilo que acabamos de crear.
)

Tamén podemos utilizalo para personalizar un tema. No exemplo completo partimos de temaClaroBase e creamos temaClaro modificando só o que nos interesa: os títulos aparecen en negra e os FilledButton teñen máis espazo interior.

Neste exemplo personalizamos só o tema claro. Para conservar os mesmos axustes no escuro, tamén debemos aplicalos ao seu tema.

💡 Un estilo escrito directamente nun widget ten prioridade sobre o estilo herdado do tema. É recomendable reservar estes estilos locais para excepcións. Se queremos modificar todos os botóns do mesmo tipo, debemos facelo no tema, por exemplo mediante filledButtonTheme.

Adaptar un estilo de texto con copyWith
Adaptar un estilo de texto con copyWith

🌗 Tema claro e escuro

Flutter permite definir un tema claro e outro escuro para que a aplicación poida adaptarse á preferencia do usuario ou do dispositivo.

En MaterialApp utilizamos principalmente estas tres propiedades:

PropiedadePara que serve?
themeDefine o tema claro.
darkThemeDefine o tema escuro.
themeModeIndica que tema debe utilizarse.

themeMode pode ter tres valores:

  • ThemeMode.light: utiliza sempre o tema claro.
  • ThemeMode.dark: utiliza sempre o tema escuro.
  • ThemeMode.system: utiliza a configuración do dispositivo.

Por exemplo:

MaterialApp(
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.blue,
    ),
  ),
  darkTheme: ThemeData(
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.blue,
      brightness: Brightness.dark, // Xera cores para o modo escuro.
    ),
  ),
  themeMode: ThemeMode.system,
  home: const PantallaCentro(),
)

brightness: Brightness.dark indica que a combinación de cores debe estar preparada para un fondo escuro.

Neste caso, a aplicación cambia automaticamente entre o tema claro e o escuro segundo a configuración do dispositivo.

📌 Se non definimos darkTheme, Flutter utiliza theme tamén cando se solicita o modo escuro.

Para que ambos os modos funcionen correctamente, evita fixar directamente cores como Colors.black para o texto ou Colors.white para os fondos. É preferible utilizar as cores e os estilos proporcionados polo tema, xa que se adaptarán ao modo claro ou escuro.

Adaptar o modo claro ou escuro á configuración do sistema
Adaptar o modo claro ou escuro á configuración do sistema

🧪 Exemplo completo

Cambia ThemeMode.light por ThemeMode.dark para comparar o título, a tarxeta e o botón. Con ThemeMode.system, o resultado depende da configuración do sistema.

🔗 DartPad:

?. evita chamar a copyWith se o estilo consultado é null, como vimos en Dart. A AppBar pode ter un fondo claro no modo claro: non todos os compoñentes usan primary como fondo.

No Tema 3.3 engadiremos un interruptor que cambia o modo coa aplicación en marcha. Aquí practicamos primeiro a configuración visual.

A mesma pantalla cos temas claro e escuro
A mesma pantalla cos temas claro e escuro

🔤 Compartir a fonte

Se xa instalaches google_fonts e engadiches o seu import, podes incluír isto dentro de ThemeData:

fontFamily: GoogleFonts.pacifico().fontFamily, // Fonte común deste tema.

Configúraa nos dous temas se queres conservar a mesma fonte ao cambiar de modo. Podes separar as definicións dos temas nun ficheiro como lib/tema.dart e importalo desde main.dart cando o proxecto medre.

Aplicar a fonte Pacifico ao tema con Google Fonts
Aplicar a fonte Pacifico ao tema con Google Fonts

📚 Consulta: