Material 3-farveskemaer og seed-farver
Generér harmoniske farveskemaer ud fra én seed-farve med ColorScheme.fromSeed.
Material 3-farveskemaer og seed-farver er en gratis Mobiludvikling med Flutter-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Mobiludvikling med Flutter, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Mobiludvikling med Flutter-kurset indeholder 4 lektioner i alt.
Hvad er et farveskema i Material 3?
Material 3 (M3) introducerede et struktureret farveskema — et sæt navngivne farveroller, som hele din app bruger konsekvent. I stedet for at sprede rå hex-værdier på tværs af widgets definerer du roller som primary, onPrimary, surface, error, og Flutter anvender dem automatisk gennem sit tematiseringssystem.
- primary — brandfarven, der bruges til knapper, FAB'er og aktive faner
- onPrimary — tekst og ikoner, der tegnes oven på primary
- surface — baggrunden for kort, paneler og dialogbokse
- onSurface — tekst, der tegnes på overflader
- error / onError — farver til validering og advarsler
Hver rolle findes både i en lys og en mørk variant, så du kan understøtte begge temaer med én definition af farveskemaet.
Problemet, som ColorScheme.fromSeed løser
Før M3 skulle udviklere selv vælge hver farverolle — primary, secondary, tertiary, overflader, beholdere og deres "on"-modstykker. Det er mere end 25 værdier, og det er fejlbehæftet manuelt at få de tilgængelige kontrastforhold til at passe.
ColorScheme.fromSeed løser dette ved at modtage en enkelt startfarve og bruge Googles algoritme for HCT-farverummet (Hue, Chroma, Tone) til automatisk at generere en komplet, harmonisk palet, der overholder WCAG.
- Ét input → mere end 25 outputroller
- Garanteret kontrast mellem par af forgrund og baggrund
- Lyse og mørke varianter fra den samme startfarve
- Konsekvent med designsproget Material You
Dit første ColorScheme.fromSeed
Det er enkelt at bruge ColorScheme.fromSeed. Send den til ThemeData i din MaterialApp. Flutter klarer resten.
Parameteren seedColor accepterer enhver Color — typisk din brandfarve. Flutter udleder derefter hele paletten ud fra den.
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),
),
);
}
}Lyst og mørkt tema fra den samme startfarve
En af de største fordele ved ColorScheme.fromSeed er, at du kan generere både et lyst og et mørkt tema ud fra den samme grundfarve, så det visuelle udtryk er ensartet på tværs af tilstande.
Angiv parameteren brightness for at skifte mellem dem. Flutter justerer automatisk tonerne — mørke temaer bruger lysere toner af din grundfarve på mørke overflader.
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')),
),
);
}
}Adgang til farveroller i widgets
Når din ColorScheme er konfigureret, kan du få adgang til dens roller overalt via Theme.of(context).colorScheme. Det holder dine widgets adskilt fra hårdkodede farver og sørger automatisk for, at de følger lyst eller mørkt tema.
Almindelige roller, som du vil bruge i widgets:
colorScheme.primary— fremhævelsesfarve til interaktive elementercolorScheme.onPrimary— tekst- og ikonfarve på primære baggrundecolorScheme.surface— baggrunde til kort og dialogercolorScheme.onSurface— standardfarve til tekstcolorScheme.error— indikatorer for fejltilstande
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,
),
),
);
}
}Containerroller: primaryContainer og de øvrige
M3 introducerede containerroller — blødere versioner med lavere kromatisk intensitet af de grundlæggende farver, beregnet til baggrunde for UI-elementer som chips, kort og udfyldte knapper.
primaryContainer— blød primær baggrund (velegnet til valgte chips og udfyldte tonale knapper)onPrimaryContainer— tekst oven på primaryContainersecondaryContainer/tertiaryContainer— tilsvarende roller for de sekundære og tertiære palettererrorContainer— blød rød til indlejrede fejlmeddelelser
Hvis du bruger containere i stedet for den rå primary til baggrunde, får du et visuelt hierarki og sikre kontrastforhold uden manuelt at skulle justere gennemsigtigheden.
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),
),
],
),
),
);
}
}Tilsidesættelse af bestemte roller
Nogle gange passer den algoritmisk genererede farve til en bestemt rolle ikke helt med din brandvejledning. Du kan tilsidesætte individuelle roller ved at bruge ColorScheme.fromSeed(...).copyWith(...). På den måde bevarer du alle automatisk genererede roller, samtidig med at du kan fastlåse bestemte roller.
Dette mønster er nyttigt, når dit designsystem for eksempel kræver en bestemt rød farve til error, som adskiller sig fra den, HCT-algoritmen genererer.
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,
);
}Dynamisk farve: Tilpasning til baggrundsbilledet
Android 12+ understøtter dynamisk farve — systemet udtrækker en grundfarve fra brugerens baggrundsbillede og anvender den i alle apps. Flutter understøtter dette via pakken dynamic_color.
Mønstret er: Prøv at indlæse systemets farveskema, og brug din egen grundfarve som reserve, hvis det ikke er muligt (på iOS, ældre versioner af Android, eller når brugeren ikke har valgt et baggrundsbillede).
Det får din app til at føles indbygget i systemet og personlig på understøttede enheder, samtidig med at den forbliver ensartet alle andre steder.
// 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')),
),
);
},
);
}
}Forhåndsvisning af din palette med et gitter af farvefelter
Under udviklingen er det nyttigt at vise alle vigtige farveroller på skærmen, så du visuelt kan kontrollere den genererede palette. Denne fejlfindingsskærm er en hurtig måde at kontrollere kontrast og harmoni på, før du udgiver appen.
Byg et enkelt gitter, der knytter rollenavne til deres farver og de tilsvarende »on«-roller, ved hjælp af den aktuelle ColorScheme fra konteksten.
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(),
),
);
}
}Almindelige faldgruber ved farveskemaer
Undgå disse fejl, når du arbejder med M3-farveskemaer:
- Hårdkodning af hex-farver i widgets — Brug altid
Theme.of(context).colorScheme.*, så widgets reagerer på temaændringer og mørk tilstand. - Direkte brug af Colors.white / Colors.black — De fungerer ikke korrekt i mørk tilstand. Brug i stedet
colorScheme.onSurfaceellercolorScheme.surface. - Glemsel af
useMaterial3: true— Uden dette flag bruger Flutter M2-standardindstillinger, og dine M3-farveroller anvendes muligvis ikke korrekt på indbyggede widgets. - Brug af
primaryColorfra ThemeData — Det er et M2-begreb. I M3 læser alle widgets fracolorScheme. AngivThemeData.colorScheme, ikkeThemeData.primaryColor. - Uoverensstemmelse mellem lysstyrke og baggrund — Hvis du genererer et
Brightness.dark-skema og kombinerer det med et hvidt scaffold, bliver brugerfladen ulæselig.
Samling af det hele: En tematiseret appskal
Her er en komplet, minimal appskal, der demonstrerer bedste praksis: et farveskema baseret på en grundfarve, understøttelse af lyst og mørkt tema, useMaterial3: true og widgets, der læser roller fra konteksten — uden hårdkodede farver noget sted.
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),
),
);
}
}Hurtigt tjek: ColorScheme.fromSeed
Test din forståelse af, hvordan ColorScheme.fromSeed fungerer i Material 3.
Opsummering af lektionen: Material 3-farveskemaer og grundfarver
Her er, hvad du har lært i denne lektion:
- ColorScheme i M3 definerer et komplet sæt navngivne farveroller (primary, surface, error, containere og deres tilsvarende »on«-roller), som Flutter-widgets automatisk bruger.
- ColorScheme.fromSeed genererer mere end 25 roller ud fra en enkelt brandfarve ved hjælp af Googles HCT-algoritme, hvilket sikrer harmoni og tilgængelighed.
- Angiv
brightness: Brightness.lightellerBrightness.darkfor at generere passende varianter ud fra den samme grundfarve — kombiner det altid medMaterialApp.darkThemefor fuld understøttelse af mørk tilstand. - Få adgang til roller i widgets via
Theme.of(context).colorScheme— hardkod aldrig hex-værdier i widgetfiler. - Brug containerroller (
primaryContainer,onPrimaryContainer) til baggrunde for UI-komponenter; de giver et visuelt hierarki uden manuel justering af gennemsigtigheden. - Tilsidesæt individuelle roller med
.copyWith(), når en bestemt brandfarve skal være helt præcis. - På Android 12+ udtrækker dynamisk farve via pakken
dynamic_colorsystemets grundfarve; sørg altid for en reserve til andre platforme. - Angiv altid
useMaterial3: truepåThemeData, så indbyggede widgets læser korrekt fra M3-farveskemaet.
Lær Dart med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 22
- Lektioner
- 88
Ofte stillede spørgsmål
Er lektionen “Material 3-farveskemaer og seed-farver” gratis?
Ja — alle 3 lektioner i læringssporet Mobiludvikling med Flutter, inklusive “Material 3-farveskemaer og seed-farver”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Mobiludvikling med Flutter-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Material 3-farveskemaer og seed-farver”?
Generér harmoniske farveskemaer ud fra én seed-farve med ColorScheme.fromSeed. Du øver dig i Mobiludvikling med Flutter med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Mobiludvikling med Flutter?
Der kræves ingen tidligere erfaring. Mobiludvikling med Flutter på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.
Hvor lang tid tager lektionen “Material 3-farveskemaer og seed-farver”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Mobiludvikling med Flutter-lektion?
Ja. Alle Mobiludvikling med Flutter-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Material 3-farveskemaer og seed-farver
- Dynamiske farver og adaptive lyse/mørke temaer
- Brugerdefineret ThemeExtension til brandtokens
- Responsiv typografi og tematisering af komponenter