Mobilutvikling med Flutter · leksjon

Material 3-fargeskjemaer og seed-farger

Generer harmoniske fargeskjemaer fra én seed-farge med ColorScheme.fromSeed.

Leksjon 1 av 413 trinn

Material 3-fargeskjemaer og seed-farger er en gratis leksjon i Mobilutvikling med Flutter på CoddyKit. Dette er leksjon 1 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Mobilutvikling med Flutter, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Mobilutvikling med Flutter inneholder totalt 4 leksjoner.

Hva er et fargeskjema i Material 3?

Material 3 (M3) introduserte et strukturert fargeskjema – et sett med navngitte fargeroller som hele appen bruker konsekvent. I stedet for å spre rå heksadesimale verdier rundt i widgetene definerer De roller som primary, onPrimary, surface og error, og Flutter bruker dem automatisk gjennom temamotoren.

  • primary — merkevarefargen som brukes for knapper, FAB-er og aktive faner
  • onPrimary — tekst/ikoner som tegnes oppå primary
  • surface — bakgrunn for kort, ark og dialogbokser
  • onSurface — tekst som tegnes på overflater
  • error / onError — farger for validering og varsler

Hver rolle finnes i både en lys og en mørk variant, slik at De kan støtte begge temaene med én definisjon av fargeskjemaet.

Problemet ColorScheme.fromSeed løser

Før M3 måtte utviklere velge hver fargerolle manuelt – primary, secondary, tertiary, overflater, beholdere og de tilsvarende «on»-variantene. Det er mer enn 25 verdier, og det er lett å gjøre feil når tilgjengelige kontrastforhold skal sikres manuelt.

ColorScheme.fromSeed løser dette ved å ta imot én startfarge og bruke Googles algoritme for HCT-fargerommet (Hue, Chroma, Tone) til å generere en komplett, harmonisk og WCAG-tilgjengelig palett automatisk.

  • Én inndata → mer enn 25 utdataroller
  • Garantert kontrast mellom par av forgrunn og bakgrunn
  • Lyse og mørke varianter fra samme startfarge
  • Konsekvent med designspråket Material You

Ditt første ColorScheme.fromSeed

Det er enkelt å bruke ColorScheme.fromSeed. Send det inn i ThemeData i MaterialApp. Flutter ordner resten.

Parameteren seedColor godtar enhver Color – vanligvis merkevarefargen Deres. Flutter utleder deretter hele paletten 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 samme startfarge

En av de største fordelene med ColorScheme.fromSeed er at De kan generere både et lyst og et mørkt tema fra den samme startfargen, slik at det visuelle uttrykket blir konsekvent på tvers av modusene.

Send inn parameteren brightness for å bytte mellom dem. Flutter justerer tonene automatisk – mørke temaer bruker lysere toner av startfargen på mørke flater.

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')),
      ),
    );
  }
}

Tilgang til fargeroller i widgets

Når ColorScheme er konfigurert, kan De få tilgang til rollene overalt via Theme.of(context).colorScheme. Da blir widgetene frikoblet fra hardkodede farger, og de følger automatisk lyst eller mørkt modus.

Vanlige roller De kommer til å bruke i widgets:

  • colorScheme.primary — fremhevingsfarge for interaktive elementer
  • colorScheme.onPrimary — tekst- og ikonfarge på primærbakgrunner
  • colorScheme.surface — bakgrunner for kort og dialogbokser
  • colorScheme.onSurface — standard tekstfarge
  • colorScheme.error — indikatorer for feiltilstander
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-roller: primaryContainer og flere

M3 introduserte container-roller – mykere farger med lavere kromatisitet, utformet for bakgrunner til UI-elementer som chips, kort og fylte knapper.

  • primaryContainer — myk primærbakgrunn (egner seg godt for valgte chips og fylte tonale knapper)
  • onPrimaryContainer — tekst oppå primaryContainer
  • secondaryContainer / tertiaryContainer — tilsvarende roller for sekundær- og tertiærpalettene
  • errorContainer — myk rød for innebygde feilmeldinger

Ved å bruke containere i stedet for rå primary til bakgrunner får De et tydelig visuelt hierarki og trygge kontrastforhold uten å måtte justere gjennomsiktigheten manuelt.

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),
            ),
          ],
        ),
      ),
    );
  }
}

Overstyre bestemte roller

Noen ganger samsvarer ikke den algoritmisk genererte fargen for en bestemt rolle nøyaktig med retningslinjene for merkevaren. De kan overstyre enkeltroller ved å bruke ColorScheme.fromSeed(...).copyWith(...). Da beholdes alle automatisk genererte roller, samtidig som De kan fastsette bestemte roller.

Dette mønsteret er nyttig når designsystemet for eksempel krever en bestemt rødfarge for error som avviker 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 farge: Tilpasning til bakgrunnsbildet

Android 12+ støtter Dynamic Color – systemet henter ut en startfarge fra brukerens bakgrunnsbilde og bruker den i alle apper. Flutter støtter dette via pakken dynamic_color.

Mønsteret er: prøv å laste inn systemets fargeskjema, og bruk Deres egen startfarge som reserve hvis det ikke er tilgjengelig (på iOS, eldre Android-versjoner eller når brukeren ikke har angitt et bakgrunnsbilde).

Dette gjør at appen føles innebygd og personlig på støttede enheter, samtidig som den forblir konsekvent overalt ellers.

// 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åndsvis paletten med et rutenett av fargeprøver

Under utviklingen er det nyttig å vise alle viktige fargeroller på skjermen, slik at De visuelt kan kontrollere den genererte paletten. Denne feilsøkingsskjermen er en rask måte å kontrollere kontrast og harmoni på før lansering.

Bygg et enkelt rutenett som kobler rollenavn til fargene deres og de tilsvarende «on»-fargene, ved å bruke den aktive 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(),
      ),
    );
  }
}

Vanlige fallgruver med fargeskjemaer

Unngå disse feilene når De arbeider med M3-fargeskjemaer:

  • Hardkode heksadesimalfarger i widgets — Bruk alltid Theme.of(context).colorScheme.*, slik at widgetene reagerer på temaendringer og mørkt modus.
  • Bruk Colors.white / Colors.black direkte — Disse fungerer dårlig i mørkt modus. Bruk heller colorScheme.onSurface eller colorScheme.surface.
  • Glem useMaterial3: true — Uten dette flagget bruker Flutter M2-standarder, og M3-fargerollene brukes kanskje ikke riktig av innebygde widgets.
  • Bruk primaryColor fra ThemeData — Dette er et M2-konsept. I M3 leser alle widgets fra colorScheme. Angi ThemeData.colorScheme, ikke ThemeData.primaryColor.
  • Uoverensstemmelse mellom lysstyrke og bakgrunn — Hvis De genererer et Brightness.dark-skjema og kombinerer det med en hvit scaffold, blir brukergrensesnittet uleselig.

Sett alt sammen: Et tematisert appskall

Her er et komplett, minimalt appskall som demonstrerer anbefalte fremgangsmåter: seed-basert fargeskjema, støtte for lyst og mørkt modus, useMaterial3: true og widgets som leser roller fra konteksten – uten hardkodede farger noe 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),
      ),
    );
  }
}

Hurtigsjekk: ColorScheme.fromSeed

Test forståelsen Deres av hvordan ColorScheme.fromSeed fungerer i Material 3.

Oppsummering av leksjonen: Material 3-fargeskjemaer og startfarger

Dette lærte De i denne leksjonen:

  • ColorScheme i M3 definerer et komplett sett med navngitte fargeroller (primary, surface, error, containere og deres «on»-motstykker) som Flutter-widgeter bruker automatisk.
  • ColorScheme.fromSeed genererer over 25 roller fra én enkelt merkevarefarge ved hjelp av Googles HCT-algoritme, noe som sikrer harmoni og god tilgjengelighet.
  • Send inn brightness: Brightness.light eller Brightness.dark for å generere passende varianter fra den samme startfargen – kombiner alltid dette med MaterialApp.darkTheme for full støtte for mørkt modus.
  • Få tilgang til roller i widgets via Theme.of(context).colorScheme – hardkod aldri heksadesimalverdier i widgetfiler.
  • Bruk container-roller (primaryContainer, onPrimaryContainer) som bakgrunn for UI-komponenter. De gir et visuelt hierarki uten manuelle justeringer av gjennomsiktigheten.
  • Overstyr enkeltroller med .copyWith() når en bestemt merkevarefarge må være nøyaktig.
  • På Android 12+ henter Dynamic Color via pakken dynamic_color ut systemets startfarge. Sørg alltid for en reserveverdi på andre plattformer.
  • Angi alltid useMaterial3: true på ThemeData, slik at innebygde widgets leser riktig fra M3-fargeskjemaet.
Gratis å komme i gang

Lær deg Dart med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
22
Leksjoner
88

Ofte stilte spørsmål

Er leksjonen «Material 3-fargeskjemaer og seed-farger» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Mobilutvikling med Flutter, inkludert «Material 3-fargeskjemaer og seed-farger», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Mobilutvikling med Flutter inneholder totalt 4 leksjoner.

Hva lærer jeg i «Material 3-fargeskjemaer og seed-farger»?

Generer harmoniske fargeskjemaer fra én seed-farge med ColorScheme.fromSeed. Du øver på Mobilutvikling med Flutter med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Mobilutvikling med Flutter?

Ingen tidligere erfaring er nødvendig. Mobilutvikling med Flutter på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.

Hvor lang tid tar leksjonen «Material 3-fargeskjemaer og seed-farger»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Mobilutvikling med Flutter-leksjonen?

Ja. Alle Mobilutvikling med Flutter-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Material 3-fargeskjemaer og seed-farger
  2. Dynamiske farger og adaptive lyse/mørke temaer
  3. Egendefinert ThemeExtension for merkevaretokens
  4. Responsiv typografi og tematisering av komponenter
← Tilbake til Mobilutvikling med Flutter