Flutter Mobile Development · Lekcja

Dynamiczne kolory i adaptacyjne jasne oraz ciemne motywy

Dostosowuj paletę do tapety użytkownika i płynnie przełączaj się między trybem jasnym a ciemnym

Lekcja 2 z 413 kroki

Dynamiczne kolory i adaptacyjne jasne oraz ciemne motywy to bezpłatna lekcja Flutter Mobile Development na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Flutter Mobile Development, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Flutter Mobile Development zawiera 4 lekcji w sumie.

Dlaczego dynamiczny kolor ma znaczenie

Material 3 wprowadza dynamiczny kolor: paleta aplikacji może być wyprowadzana z tapety użytkownika (Android 12+), dzięki czemu interfejs sprawia wrażenie spersonalizowanego i natywnego dla urządzenia.

  • Na obsługiwanych urządzeniach system udostępnia ColorScheme utworzony na podstawie tapety.
  • Na starszych urządzeniach i innych platformach używany jest zastępczy kolor bazowy marki.
  • Ta sama logika musi generować zarówno jasny, jak i ciemny schemat.

W tej lekcji skonfigurują Państwo dynamiczny kolor, utworzą adaptacyjne jasne i ciemne motywy oraz pozwolą systemowi zdecydować, który z nich wyświetlić.

Kolor bazowy jako fundament

Nawet w przypadku dynamicznego koloru zawsze potrzebne jest rozwiązanie zastępcze. ColorScheme.fromSeed w Material 3 generuje kompletną, dostępną paletę na podstawie jednego koloru bazowego.

  • Przekaż brightness, aby uzyskać odpowiedni jasny lub ciemny wariant.
  • Wygenerowany schemat gwarantuje prawidłowy kontrast między rolami, takimi jak primary i onPrimary.
import 'package:flutter/material.dart';

final ColorScheme lightScheme = ColorScheme.fromSeed(
  seedColor: const Color(0xFF6750A4),
  brightness: Brightness.light,
);

final ColorScheme darkScheme = ColorScheme.fromSeed(
  seedColor: const Color(0xFF6750A4),
  brightness: Brightness.dark,
);

Tworzenie jasnego i ciemnego ThemeData

Element ThemeData opakowuje ColorScheme oraz style typografii i komponentów. W Material 3 należy ustawić useMaterial3: true i przekazać schemat.

  • Utwórz jeden element ThemeData dla każdej jasności.
  • Zachowaj spójność, wyprowadzając oba schematy z tego samego koloru bazowego.
ThemeData buildTheme(ColorScheme scheme) {
  return ThemeData(
    useMaterial3: true,
    colorScheme: scheme,
    appBarTheme: AppBarTheme(
      backgroundColor: scheme.surface,
      foregroundColor: scheme.onSurface,
    ),
  );
}

Pozwolenie systemowi na wybór trybu

MaterialApp przyjmuje zarówno theme (jasny), jak i darkTheme. Właściwość themeMode określa, który z nich jest aktywny.

  • ThemeMode.system automatycznie korzysta z ustawień systemu operacyjnego.
  • ThemeMode.light / ThemeMode.dark wymuszają wybrany tryb (co jest przydatne w przypadku przełącznika w aplikacji).

W trybie ThemeMode.system Flutter płynnie przełącza motyw, gdy użytkownik zmieni ustawienie trybu ciemnego w urządzeniu.

MaterialApp(
  theme: buildTheme(lightScheme),
  darkTheme: buildTheme(darkScheme),
  themeMode: ThemeMode.system,
  home: const HomePage(),
);

Odczytywanie dynamicznego koloru z systemu

Pakiet dynamic_color udostępnia paletę opartą na tapecie za pośrednictwem widżetu DynamicColorBuilder. Jego funkcja builder udostępnia opcjonalne jasne i ciemne elementy ColorScheme.

  • Jeśli urządzenie obsługuje dynamiczny kolor, oba schematy mają wartość inną niż null.
  • Jeśli nie, mają wartość null i używany jest kolor bazowy.
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';

DynamicColorBuilder(
  builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
    final light = lightDynamic ?? lightScheme;
    final dark = darkDynamic ?? darkScheme;
    return MaterialApp(
      theme: buildTheme(light),
      darkTheme: buildTheme(dark),
      themeMode: ThemeMode.system,
      home: const HomePage(),
    );
  },
);

Harmonizowanie kolorów marki

Połączenie dynamicznych kolorów tapety z kolorem marki może powodować zgrzyt wizualny. Funkcje pomocnicze harmonize przesuwają niestandardowy kolor w stronę dynamicznego koloru primary, dzięki czemu akcenty tworzą spójną całość.

  • Użyj harmonizeWith na obiekcie Color, wskazując główny kolor schematu.
  • Dzięki temu niestandardowe kolory semantyczne (sukcesu, ostrzeżenia) pozostają zgodne z marką i tapetą.
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';

ColorScheme harmonizeScheme(ColorScheme scheme) {
  return scheme.harmonized();
}

Color harmonizeBrand(Color brand, ColorScheme scheme) {
  return brand.harmonizeWith(scheme.primary);
}

Role kolorów zamiast zapisanych na stałe wartości szesnastkowych

Aby motywy mogły się dostosowywać, widżety muszą odczytywać role semantyczne z Theme.of(context).colorScheme, zamiast używać kolorów zapisanych na stałe.

  • scheme.primary wraz z scheme.onPrimary dla wyróżnionych działań.
  • scheme.surface wraz z scheme.onSurface dla teł i tekstu.
  • scheme.surfaceContainerHighest dla subtelnych kart.

Ponieważ te role zmieniają się wraz z jasnością, widżety automatycznie stają się niezależne od jasnego i ciemnego trybu.

Widget buildCard(BuildContext context) {
  final scheme = Theme.of(context).colorScheme;
  return Container(
    color: scheme.surfaceContainerHighest,
    child: Text(
      'Adaptive',
      style: TextStyle(color: scheme.onSurface),
    ),
  );
}

Czysty Dart: wybór schematu według jasności

Logika decydująca o tym, którego schematu użyć, jest napisana w zwykłym języku Dart. Oto mały, uruchamialny model reguły zastępczej: najpierw wybierz schemat dynamiczny, a jeśli nie jest dostępny, użyj schematu wyprowadzonego z koloru bazowego.

  • Odzwierciedla to wzorzec lightDynamic ?? lightScheme.
  • Nie są potrzebne widżety Fluttera — wystarczy sama reguła wyboru.
enum Brightness { light, dark }

String chooseScheme({
  required Brightness brightness,
  required bool supportsDynamic,
}) {
  final base = supportsDynamic ? 'dynamic' : 'seed';
  return '$base-${brightness.name}';
}

void main() {
  print(chooseScheme(brightness: Brightness.dark, supportsDynamic: true));
  print(chooseScheme(brightness: Brightness.light, supportsDynamic: false));
}

Przełącznik motywu w aplikacji

Użytkownicy często chcą zastąpić ustawienia systemowe. Przechowuj ThemeMode w stanie i przekazuj go do MaterialApp. ValueNotifier to lekki sposób na ponowne budowanie interfejsu po zmianie.

  • Ustaw domyślnie ThemeMode.system, aby nadal obowiązywały tapeta i tryb ciemny.
  • Pozwól przełącznikowi wybrać tryb jasny, ciemny lub ponownie systemowy.
final themeModeNotifier = ValueNotifier<ThemeMode>(ThemeMode.system);

ValueListenableBuilder<ThemeMode>(
  valueListenable: themeModeNotifier,
  builder: (context, mode, _) {
    return MaterialApp(
      theme: buildTheme(lightScheme),
      darkTheme: buildTheme(darkScheme),
      themeMode: mode,
      home: const HomePage(),
    );
  },
);

Reagowanie na efektywną jasność

W widżetach czasami trzeba sprawdzić, który tryb jest faktycznie wyświetlany (na przykład aby wybrać inną ilustrację). Odczytuj tę informację z aktywnego motywu, a nie z urządzenia, ponieważ przełącznik w aplikacji może zastąpić ustawienia systemowe.

  • Theme.of(context).brightness odzwierciedla rozstrzygnięty motyw.
  • Unikaj MediaQuery.platformBrightnessOf, gdy przełącznik może zastąpić ustawienie systemowe.
Widget heroImage(BuildContext context) {
  final isDark = Theme.of(context).brightness == Brightness.dark;
  return Image.asset(
    isDark ? 'assets/hero_dark.png' : 'assets/hero_light.png',
  );
}

Szybkie testowanie obu trybów

Przed wydaniem aplikacji zawsze sprawdzaj interfejs w obu schematach. Dwie praktyczne metody:

  • Przełącz tryb ciemny w ustawieniach urządzenia lub emulatora, aby potwierdzić, że ThemeMode.system reaguje prawidłowo.
  • Tymczasowo wymuś themeMode: ThemeMode.dark, aby wykryć kolory zapisane na stałe i tekst o niskim kontraście.

Typowe błędy to tekst w Colors.black zapisany na stałe, który znika na ciemnej powierzchni, lub niestandardowy akcent, który nigdy nie został zharmonizowany z dynamiczną paletą.

Szybkie sprawdzenie: wybór themeMode

Chcą Państwo, aby aplikacja automatycznie dopasowywała się do dynamicznych kolorów z tapety użytkownika i jednocześnie korzystała z ustawienia jasnego lub ciemnego trybu w systemie operacyjnym, a w przyszłości nadal umożliwiała opcjonalne nadpisanie tego ustawienia w aplikacji. Jaka jest właściwa konfiguracja bazowa?

Podsumowanie: adaptacyjne motywy Material 3

Utworzył(a) Pan(i) paletę, która dopasowuje się zarówno do tapety, jak i jasności:

  • Rezerwowy schemat bazowy: ColorScheme.fromSeed dla jasnego i ciemnego motywu, gdy kolor dynamiczny jest niedostępny.
  • Kolor dynamiczny: DynamicColorBuilder dostarcza schematy na podstawie tapety, a ?? seedScheme zapewnia wartość rezerwową.
  • Harmonizacja: dopasowanie kolorów marki i niestandardowych kolorów do dynamicznego koloru podstawowego.
  • Role semantyczne: odczytywanie ról colorScheme zamiast używania zakodowanych na stałe wartości szesnastkowych, aby widżety automatycznie się przełączały.
  • Kontrola trybu: domyślnie themeMode: ThemeMode.system, z opcjonalnym przełącznikiem ValueNotifier.

Proszę dostosowywać interfejs do użytkownika, zapewniać rozsądne wartości rezerwowe i nigdy nie kodować na stałe koloru, który można odczytać ze schematu.

Bezpłatny start

Ucz się Dart dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
22
Lekcje
88

Często zadawane pytania

Czy lekcja „Dynamiczne kolory i adaptacyjne jasne oraz ciemne motywy” jest bezpłatna?

Tak — pełny tekst „Dynamiczne kolory i adaptacyjne jasne oraz ciemne motywy” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Flutter Mobile Development, przejdź na CoddyKit PRO. Kurs Flutter Mobile Development zawiera 4 lekcji w sumie.

Co nauczysz się w „Dynamiczne kolory i adaptacyjne jasne oraz ciemne motywy”?

Dostosowuj paletę do tapety użytkownika i płynnie przełączaj się między trybem jasnym a ciemnym Ćwiczysz Flutter Mobile Development z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Flutter Mobile Development?

Nie wymagamy żadnego doświadczenia. Flutter Mobile Development w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Dynamiczne kolory i adaptacyjne jasne oraz ciemne motywy”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Flutter Mobile Development?

Tak. Każda lekcja Flutter Mobile Development zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Schematy kolorów Material 3 i kolory bazowe
  2. Dynamiczne kolory i adaptacyjne jasne oraz ciemne motywy
  3. Niestandardowe ThemeExtension dla tokenów marki
  4. Responsywna typografia i motywy komponentów
← Powrót do Flutter Mobile Development