Schemi colore Material 3 e colori seed
Generi schemi colore armoniosi da un singolo colore seed usando ColorScheme.fromSeed.
Schemi colore Material 3 e colori seed è una lezione Flutter Mobile Development gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Flutter Mobile Development, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Flutter Mobile Development include 4 lezioni in totale.
Parti di questa lezione non sono ancora state tradotte e vengono mostrate in inglese.
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 elementscolorScheme.onPrimary— text/icon color on primary backgroundscolorScheme.surface— card and dialog backgroundscolorScheme.onSurface— default text colorcolorScheme.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 primaryContainersecondaryContainer/tertiaryContainer— analogous roles for secondary and tertiary paletteserrorContainer— 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.onSurfaceorcolorScheme.surfaceinstead. - 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
primaryColorfrom ThemeData — That's an M2 concept. In M3, all widgets read fromcolorScheme. SetThemeData.colorScheme, notThemeData.primaryColor. - Mismatching brightness and background — Generating a
Brightness.darkscheme 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.lightorBrightness.darkto generate appropriate variants from the same seed — always pair withMaterialApp.darkThemefor 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_colorpackage extracts the system seed; always provide a fallback for other platforms. - Always set
useMaterial3: trueonThemeDataso built-in widgets read from the M3 color scheme correctly.
Impara Dart con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 22
- Lezioni
- 88
Domande Frequenti
La lezione «Schemi colore Material 3 e colori seed» è gratuita?
Sì — il testo completo di «Schemi colore Material 3 e colori seed» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Flutter Mobile Development, passa a CoddyKit PRO. Il corso Flutter Mobile Development include 4 lezioni in totale.
Cosa imparerò in «Schemi colore Material 3 e colori seed»?
Generi schemi colore armoniosi da un singolo colore seed usando ColorScheme.fromSeed. Eserciti Flutter Mobile Development con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Flutter Mobile Development?
Non è richiesta alcuna esperienza precedente. Flutter Mobile Development su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Schemi colore Material 3 e colori seed»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Flutter Mobile Development?
Sì. Ogni lezione Flutter Mobile Development include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Schemi colore Material 3 e colori seed
- Colore dinamico e temi chiaro/scuro adattivi
- ThemeExtension personalizzata per i token del brand
- Tipografia responsive e tematizzazione dei componenti