Kodokon kodokon.com

Themes: ThemeData, Material 3 und Dark Mode

Zentralisiere Farben und Typografie in ThemeData, erzeuge mit ColorScheme.fromSeed eine Material-3-Palette und biete mühelos einen Dark Mode an.

9 Min. · 3 Fragen

Diese Lektion in Kodokon öffnen

Aufzuhören, Widget für Widget zu stylen, ist ein professioneller Meilenstein: ThemeData zentralisiert Farben, Typografie und Formen für die gesamte App. Mit Material 3 (seit Flutter 3.16 standardmäßig aktiv) beginnt alles beim ColorScheme: ColorScheme.fromSeed leitet aus einer einzigen Seed-Farbe eine vollständige, harmonische und barrierefreie Palette ab.

DART
import 'package:flutter/material.dart';

void main() {
  runApp(const ShopApp());
}

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

  @override
  Widget build(BuildContext context) {
    const seed = Colors.teal;
    return MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: seed,
        ),
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: seed,
          brightness: Brightness.dark,
        ),
      ),
      themeMode: ThemeMode.system,
      home: Scaffold(
        appBar: AppBar(title: const Text('Shop')),
        body: const Center(child: Text('Welcome')),
      ),
    );
  }
}
Zwei Themes, aus einer einzigen Seed-Farbe erzeugt.

Erfinde in deinen Widgets nichts neu: Lies das umgebende Theme mit Theme.of(context). Das colorScheme stellt semantische Rollen bereit (primary, onPrimary, primaryContainer, surface und so weiter), und textTheme stellt benannte Stile bereit (titleMedium, bodyLarge und so weiter). Ein so geschriebenes Widget passt sich automatisch an das helle wie an das dunkle Theme an.

DART
import 'package:flutter/material.dart';

class PriceTag extends StatelessWidget {
  const PriceTag({super.key, required this.price});

  final double price;

  @override
  Widget build(BuildContext context) {
    final colors = Theme.of(context).colorScheme;
    final text = Theme.of(context).textTheme;
    return Container(
      padding: const EdgeInsets.symmetric(
        horizontal: 12,
        vertical: 6,
      ),
      decoration: BoxDecoration(
        color: colors.primaryContainer,
        borderRadius: BorderRadius.circular(8),
      ),
      child: Text(
        '$price €',
        style: text.titleMedium?.copyWith(
          color: colors.onPrimaryContainer,
        ),
      ),
    );
  }
}
Keine fest codierte Farbe: Das Widget folgt dem aktiven Theme.

Um weiterzugehen, konfiguriere die Komponenten-Themes: Jede Widget-Familie (App-Bars, Buttons, Eingabefelder) akzeptiert in ThemeData ein eigenes Theme. Du legst das Padding deiner Buttons oder die Zentrierung deiner Titel einmal fest, und jede Instanz erbt es, ohne einen einzigen lokalen Stil.

DART
import 'package:flutter/material.dart';

final ThemeData appTheme = ThemeData(
  colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.teal,
  ),
  appBarTheme: const AppBarTheme(
    centerTitle: true,
    elevation: 0,
  ),
  filledButtonTheme: FilledButtonThemeData(
    style: FilledButton.styleFrom(
      padding: const EdgeInsets.symmetric(
        horizontal: 24,
        vertical: 12,
      ),
    ),
  ),
);
Komponenten-Einstellungen gelten in der ganzen App.

Wissenscheck

Stelle sicher, dass du die wichtigsten Punkte dieser Lektion behalten hast.

  1. Was erzeugt ColorScheme.fromSeed(seedColor: ...)?
    • Eine einzige, leicht aufgehellte Farbe
    • Eine vollständige, kohärente Material-3-Palette, abgeleitet aus der Seed-Farbe
    • Einen Farbverlauf für Hintergründe
    • Nur ein dunkles Theme
  2. Wie sorgt man dafür, dass die App der Hell-/Dunkel-Einstellung des Systems folgt?
    • Nur theme angeben; der Rest passiert automatisch
    • theme und darkTheme angeben und themeMode auf ThemeMode.system setzen
    • setState aufrufen, wenn sich die Helligkeit ändert
    • In jedem Widget MediaQuery lesen
  3. Warum color: Theme.of(context).colorScheme.primary schreiben statt color: Colors.blue?
    • Es ist kürzer zu schreiben
    • Die Farbe passt sich dem aktiven Theme an und bleibt in der ganzen App konsistent
    • Colors.blue ist in Material 3 veraltet