Flutter Mobile Development · Lektion

Material-3-Farbschemata und Seed-Farben

Erzeugen Sie harmonische Farbschemata aus einer einzigen Seed-Farbe mit ColorScheme.fromSeed.

Lektion 1 von 413 Schritte

Material-3-Farbschemata und Seed-Farben ist eine kostenlose Flutter Mobile Development-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Flutter Mobile Development-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Flutter Mobile Development-Kurs umfasst insgesamt 4 Lektionen.

Teile dieser Lektion wurden noch nicht übersetzt und werden auf Englisch angezeigt.

What Is a Color Scheme in Material 3?

Material 3 (M3) introduced a structured color scheme — a set of named color roles that your entire app uses consistently. Instead of scattering raw hex values across widgets, you define roles like primary, onPrimary, surface, error, and Flutter's theming engine applies them automatically.

  • primary — the brand color used for buttons, FABs, active tabs
  • onPrimary — text/icons drawn on top of primary
  • surface — background of cards, sheets, dialogs
  • onSurface — text drawn on surfaces
  • error / onError — validation and alert colors

Every role comes in both a light and a dark variant, letting you support both themes with one color scheme definition.

The Problem ColorScheme.fromSeed Solves

Before M3, developers had to hand-pick every color role — primary, secondary, tertiary, surfaces, containers, and their 'on' counterparts. That's 25+ values, and getting accessible contrast ratios right manually is error-prone.

ColorScheme.fromSeed solves this by accepting a single seed color and using Google's HCT color space algorithm (Hue, Chroma, Tone) to generate a full, harmonious, WCAG-accessible palette automatically.

  • One input → 25+ output roles
  • Guaranteed contrast between foreground and background pairs
  • Light and dark variants from the same seed
  • Consistent with the Material You design language

Your First ColorScheme.fromSeed

Using ColorScheme.fromSeed is straightforward. Pass it to ThemeData inside your MaterialApp. Flutter does the rest.

The seedColor parameter accepts any Color — typically your brand color. Flutter then derives the entire palette from it.

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'M3 Theming Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF6750A4), // brand purple
        ),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Color Scheme Demo')),
      body: const Center(child: Text('Hello Material 3')),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        child: const Icon(Icons.palette),
      ),
    );
  }
}

Light and Dark from the Same Seed

One of the biggest wins of ColorScheme.fromSeed is that you can generate both a light and a dark theme from the same seed color, ensuring visual consistency across modes.

Pass the brightness parameter to switch between them. Flutter adjusts tones automatically — dark themes use lighter tones of your seed on dark surfaces.

import 'package:flutter/material.dart';

const Color _brandColor = Color(0xFF00897B); // teal brand

ThemeData lightTheme() => ThemeData(
      colorScheme: ColorScheme.fromSeed(
        seedColor: _brandColor,
        brightness: Brightness.light,
      ),
      useMaterial3: true,
    );

ThemeData darkTheme() => ThemeData(
      colorScheme: ColorScheme.fromSeed(
        seedColor: _brandColor,
        brightness: Brightness.dark,
      ),
      useMaterial3: true,
    );

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: lightTheme(),
      darkTheme: darkTheme(),
      themeMode: ThemeMode.system, // follows device setting
      home: const Scaffold(
        body: Center(child: Text('Adaptive theme')),
      ),
    );
  }
}

Accessing Color Roles in Widgets

Once your ColorScheme is set up, access its roles anywhere via Theme.of(context).colorScheme. This keeps your widgets decoupled from hard-coded colors and automatically respects light/dark mode.

Common roles you will use in widgets:

  • colorScheme.primary — highlight color for interactive elements
  • colorScheme.onPrimary — text/icon color on primary backgrounds
  • colorScheme.surface — card and dialog backgrounds
  • colorScheme.onSurface — default text color
  • colorScheme.error — error state indicators
import 'package:flutter/material.dart';

class StatusBadge extends StatelessWidget {
  final String label;
  final bool isActive;

  const StatusBadge({super.key, required this.label, required this.isActive});

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;

    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
      decoration: BoxDecoration(
        color: isActive ? cs.primaryContainer : cs.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(20),
      ),
      child: Text(
        label,
        style: TextStyle(
          color: isActive ? cs.onPrimaryContainer : cs.onSurfaceVariant,
          fontWeight: FontWeight.w600,
        ),
      ),
    );
  }
}

Container Roles: primaryContainer and Friends

M3 introduced container roles — softer, lower-chroma versions of core colors designed for backgrounds of UI elements like chips, cards, and filled buttons.

  • primaryContainer — soft primary background (great for selected chips, filled tonal buttons)
  • onPrimaryContainer — text on top of primaryContainer
  • secondaryContainer / tertiaryContainer — analogous roles for secondary and tertiary palettes
  • errorContainer — soft red for inline error banners

Using containers instead of raw primary for backgrounds gives you visual hierarchy and keeps contrast ratios safe without manually adjusting opacity.

import 'package:flutter/material.dart';

class InfoCard extends StatelessWidget {
  final String title;
  final String body;

  const InfoCard({super.key, required this.title, required this.body});

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;

    return Card(
      color: cs.primaryContainer,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              title,
              style: Theme.of(context).textTheme.titleMedium?.copyWith(
                    color: cs.onPrimaryContainer,
                    fontWeight: FontWeight.bold,
                  ),
            ),
            const SizedBox(height: 8),
            Text(
              body,
              style: TextStyle(color: cs.onPrimaryContainer),
            ),
          ],
        ),
      ),
    );
  }
}

Overriding Specific Roles

Sometimes the algorithmically generated color for a specific role doesn't match your brand guide exactly. You can override individual roles by using ColorScheme.fromSeed(...).copyWith(...). This keeps all the auto-generated roles while letting you pin specific ones.

This pattern is useful when, for example, your design system requires an exact red for error that differs from what the HCT algorithm produces.

import 'package:flutter/material.dart';

ThemeData buildTheme() {
  // Start from seed, then pin specific roles
  final base = ColorScheme.fromSeed(
    seedColor: const Color(0xFF1565C0), // deep blue brand
  );

  return ThemeData(
    colorScheme: base.copyWith(
      // Exact error red from our design system
      error: const Color(0xFFB00020),
      onError: Colors.white,
      // Pin tertiary to our accent orange
      tertiary: const Color(0xFFE65100),
      onTertiary: Colors.white,
    ),
    useMaterial3: true,
  );
}

Dynamic Color: Adapting to Wallpaper

Android 12+ supports Dynamic Color — the system extracts a seed color from the user's wallpaper and applies it to all apps. Flutter supports this via the dynamic_color package.

The pattern is: try to load the system color scheme; fall back to your own seed if unavailable (iOS, older Android, or when the user hasn't set a wallpaper).

This makes your app feel native and personalized on supported devices while remaining consistent everywhere else.

// pubspec.yaml: dynamic_color: ^1.7.0

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

const Color _fallbackSeed = Color(0xFF6750A4);

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

  @override
  Widget build(BuildContext context) {
    return DynamicColorBuilder(
      builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
        final lightScheme = lightDynamic ??
            ColorScheme.fromSeed(
              seedColor: _fallbackSeed,
              brightness: Brightness.light,
            );

        final darkScheme = darkDynamic ??
            ColorScheme.fromSeed(
              seedColor: _fallbackSeed,
              brightness: Brightness.dark,
            );

        return MaterialApp(
          theme: ThemeData(colorScheme: lightScheme, useMaterial3: true),
          darkTheme: ThemeData(colorScheme: darkScheme, useMaterial3: true),
          themeMode: ThemeMode.system,
          home: const Scaffold(
            body: Center(child: Text('Dynamic Color')),
          ),
        );
      },
    );
  }
}

Previewing Your Palette with a Color Swatch Grid

While developing, it's useful to render all key color roles on-screen so you can verify the generated palette visually. This debug screen is a quick way to check contrast and harmony before shipping.

Build a simple grid that maps role names to their colors and 'on' counterparts, using the live ColorScheme from context.

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;

    final roles = [
      ('Primary', cs.primary, cs.onPrimary),
      ('PrimaryContainer', cs.primaryContainer, cs.onPrimaryContainer),
      ('Secondary', cs.secondary, cs.onSecondary),
      ('SecondaryContainer', cs.secondaryContainer, cs.onSecondaryContainer),
      ('Tertiary', cs.tertiary, cs.onTertiary),
      ('Surface', cs.surface, cs.onSurface),
      ('Error', cs.error, cs.onError),
      ('ErrorContainer', cs.errorContainer, cs.onErrorContainer),
    ];

    return Scaffold(
      appBar: AppBar(title: const Text('Color Palette')),
      body: ListView(
        children: roles.map((r) {
          final (name, bg, fg) = r;
          return Container(
            height: 56,
            color: bg,
            alignment: Alignment.centerLeft,
            padding: const EdgeInsets.symmetric(horizontal: 16),
            child: Text(name, style: TextStyle(color: fg, fontWeight: FontWeight.w500)),
          );
        }).toList(),
      ),
    );
  }
}

Common Pitfalls with Color Schemes

Avoid these mistakes when working with M3 color schemes:

  • Hard-coding hex colors in widgets — Always use Theme.of(context).colorScheme.* so widgets respond to theme changes and dark mode.
  • Using Colors.white / Colors.black directly — These break in dark mode. Use colorScheme.onSurface or colorScheme.surface instead.
  • Forgetting useMaterial3: true — Without this flag, Flutter uses M2 defaults and your M3 color roles may not be applied correctly to built-in widgets.
  • Using primaryColor from ThemeData — That's an M2 concept. In M3, all widgets read from colorScheme. Set ThemeData.colorScheme, not ThemeData.primaryColor.
  • Mismatching brightness and background — Generating a Brightness.dark scheme but pairing it with a white scaffold will produce unreadable UI.

Putting It All Together: A Themed App Shell

Here is a complete minimal app shell that demonstrates best practices: seed-based color scheme, light/dark support, useMaterial3: true, and widgets that read roles from context — no hard-coded colors anywhere.

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

const Color _seed = Color(0xFF2E7D32); // forest green brand

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Green Theme',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: _seed,
          brightness: Brightness.light,
        ),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: _seed,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      themeMode: ThemeMode.system,
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;
    return Scaffold(
      backgroundColor: cs.surface,
      appBar: AppBar(
        title: Text('Dashboard', style: TextStyle(color: cs.onPrimary)),
        backgroundColor: cs.primary,
      ),
      body: Center(
        child: FilledButton.icon(
          onPressed: () {},
          icon: const Icon(Icons.eco),
          label: const Text('Go Green'),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        backgroundColor: cs.tertiary,
        foregroundColor: cs.onTertiary,
        child: const Icon(Icons.add),
      ),
    );
  }
}

Quick Check: ColorScheme.fromSeed

Test your understanding of how ColorScheme.fromSeed works in Material 3.

Lesson Recap: Material 3 Color Schemes and Seed Colors

Here's what you learned in this lesson:

  • ColorScheme in M3 defines a full set of named color roles (primary, surface, error, containers, and their 'on' counterparts) that Flutter widgets consume automatically.
  • ColorScheme.fromSeed generates all 25+ roles from a single brand color using Google's HCT algorithm, guaranteeing harmony and accessibility.
  • Pass brightness: Brightness.light or Brightness.dark to generate appropriate variants from the same seed — always pair with MaterialApp.darkTheme for full dark mode support.
  • Access roles in widgets via Theme.of(context).colorScheme — never hard-code hex values in widget files.
  • Use container roles (primaryContainer, onPrimaryContainer) for backgrounds of UI components; they provide visual hierarchy without manual opacity tweaks.
  • Override individual roles with .copyWith() when a specific brand color must be exact.
  • On Android 12+, Dynamic Color via the dynamic_color package extracts the system seed; always provide a fallback for other platforms.
  • Always set useMaterial3: true on ThemeData so built-in widgets read from the M3 color scheme correctly.
Kostenlos starten

Lerne Dart mit einem KI-Tutor — kostenlos

Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.

Kurse
22
Lektionen
88

Häufig gestellte Fragen

Ist die Lektion „Material-3-Farbschemata und Seed-Farben“ kostenlos?

Ja — der vollständige Text von „Material-3-Farbschemata und Seed-Farben“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Flutter Mobile Development-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Flutter Mobile Development-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Material-3-Farbschemata und Seed-Farben“?

Erzeugen Sie harmonische Farbschemata aus einer einzigen Seed-Farbe mit ColorScheme.fromSeed. Du übst Flutter Mobile Development mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Flutter Mobile Development zu starten?

Keine Vorkenntnisse erforderlich. Flutter Mobile Development auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.

Wie lange dauert die Lektion „Material-3-Farbschemata und Seed-Farben“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Flutter Mobile Development-Lektion Code schreiben und ausführen?

Ja. Jede Flutter Mobile Development-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Material-3-Farbschemata und Seed-Farben
  2. Dynamische Farben und adaptive helle/dunkle Themes
  3. Eigene ThemeExtension für Brand-Tokens
  4. Responsive Typografie und Theming von Komponenten
← Zurück zu Flutter Mobile Development