Theme a ThemeData — ústřední mechanismy motivace ve Flutter, které umožňují globálně nastavit barvy, písma, okraje a styly komponent pro celou aplikaci. ThemeData je konfigurační objekt předávaný do MaterialApp prostřednictvím parametru theme. Podle oficiální dokumentace Flutter (2026) správné nastavení ThemeData snižuje množství duplicitního kódu stylování o 70–80% a zajišťuje jednotný vzhled obrazovek. Vestavěný systém dědičnosti umožňuje přepsání motivu na úrovni jednotlivých widgetů pomocí Theme.of(context).
Hlavní body
ThemeData — třída obsahující úplný popis vizuálního stylu aplikace Material. Předává se do MaterialApp prostřednictvím parametru theme nebo darkTheme a je zděděna všemi podřízenými widgety. Každý widget Material Design používá ThemeData k získání svých stylů: barvy tlačítek, velikosti AppBar, styly textu, okraje karet a ikony.
Základem ThemeData je ColorScheme, který definuje primární, sekundární, surface, error a další barvy. Z těchto barev se automaticky vypočítávají stavy (hover, focus, pressed) pro všechny komponenty Material. Například ElevatedButton používá primární barvu pro pozadí a onPrimary pro text — bez další konfigurace.
Widget Theme — je InheritedWidget, který šíří motiv dolů stromem widgetů. Libovolný widget může získat aktuální motiv pomocí Theme.of(context) a také vytvořit nový motiv na základě stávajícího s přepsanými hodnotami pomocí Theme.copyWith nebo ThemeData.copyWith.
Závěr: ThemeData — jednotný zdroj stylů aplikace. Začněte vývoj definováním ThemeData — to určuje vizuální jazyk celého projektu a zabraňuje roztříštěným stylům na různých obrazovkách.
ColorScheme — ústřední prvek motivace v Material 3. Nahrazuje zastaralé primarySwatch a primaryColor a poskytuje kompletní sadu barev pro všechny stavy a komponenty.
ColorScheme obsahuje 12 základních barev: primary, onPrimary, secondary, onSecondary, surface, onSurface, error, onError, background, onBackground, outline a shadow. Pro každou barvu se automaticky vypočítávají varianty light a dark, stejně jako barvy pro stavy hover, focus, pressed a dragged. Při zadání pouze primary framework automaticky vygeneruje zbývající barvy pomocí ColorScheme.fromSeed.
Metoda ColorScheme.fromSeed (Material 3) přijímá základní barvu seedColor a generuje úplnou harmonickou paletu na základě algoritmu Material Design 3. To eliminuje ruční výběr komplementárních a analogických barev. Stačí předat jednu hlavní barvu značky a ColorScheme.fromSeed vytvoří konzistentní paletu pro celý systém Material.
Závěr: v nových projektech používejte ColorScheme.fromSeed pro generování palety. Pro kompatibilitu s Material 2 — primarySwatch. ColorScheme je povinné minimum pro Material 3.
TextTheme — část ThemeData definující styly textu pro všechny úrovně nadpisů, podnadpisů, těla a popisků. Material Design definuje 15 stylů textu: headlineLarge, headlineMedium, headlineSmall, titleLarge, titleMedium a další.
Typografie se nastavuje buď pomocí GoogleFonts pro automatické načítání písem, nebo pomocí vestavěného Theme.of(context).textTheme s vlastními TextStyle. GoogleFonts poskytuje stovky písem prostřednictvím balíčku google_fonts, který je po prvním načtení ukládá do lokální mezipaměti. Alternativa — vložení písem do assets projektu prostřednictvím pubspec.yaml.
Pro adaptivní typografii TextTheme podporuje MediaQuery.textScaleFactor — při zvětšení systémového písma se všechny styly textu proporcionálně škálují. Dále lze nastavit různé velikosti písma pro různé formáty pomocí isTest v závislosti na MediaQuery.size.width.
Závěr: definujte TextTheme v ThemeData a používejte Theme.of(context).textTheme pro všechny textové prvky. To zajišťuje jednotnost písem a zjednodušuje globální změny typografie.
Theme — InheritedWidget, který šíří motiv od rodiče k potomkům. Každý podřízený widget může jak číst aktuální motiv pomocí Theme.of(context), tak vytvořit svou vlastní kopii se změnami pomocí ThemeData.copyWith.
Mechanismus dědičnosti: pokud je widget zabalen do Theme s novými daty, všichni jeho potomci vidí přepsaný motiv, zatímco widgety mimo toto zabalení vidí originální. To umožňuje například izolovat styly pro konkrétní obrazovku: nadpis používá vlastní motiv se změněným AppBarTheme a zbytek aplikace používá standardní.
Vnoření Theme může být neomezené. Flutter používá hierarchické vyhledávání: při volání Theme.of(context) framework stoupá stromem nahoru k prvnímu Theme a vrací jeho motiv. Pokud není nalezen žádný Theme — je vyvolána výjimka. Proto MaterialApp vždy zabalí aplikaci do Theme.
Závěr: dědičnost Theme — flexibilní mechanismus pro izolaci stylů. Používejte přepsání motivu pro jednotlivé obrazovky bez duplikování obecné konfigurace.
Dark theme — vestavěná schopnost Flutter přepínat mezi světlým a tmavým motivem. ThemeData je uložena v parametrech theme (světlý) a darkTheme (tmavý) MaterialApp. Parametr themeMode spravuje režim: ThemeMode.light (vždy světlý), ThemeMode.dark (vždy tmavý) nebo ThemeMode.system (sleduje systémová nastavení).
Při implementaci tmavého motivu není nutné vytvářet všechny styly znovu. Stačí předat ColorScheme.fromSeed(seedColor, brightness: Brightness.dark) v darkTheme. Framework automaticky upraví barvy pro tmavé pozadí: surface se stane tmavě šedým, text světlým. Ostatní podmotivy (AppBarTheme, CardTheme, BottomNavigationBarTheme) se dědí ze světlé verze, pokud nejsou explicitně přepsány.
Pro plynulý přechod mezi motivy Flutter poskytuje animaci prostřednictvím AnimatedTheme. Při změně themeMode jsou barvy a styly animovány, což vytváří vizuálně příjemné přepínání. AnimatedTheme používá Duration a Curve pro nastavení rychlosti animace.
Závěr: dark theme se implementuje pomocí darkTheme a ColorScheme.fromSeed s brightness: Brightness.dark. Používejte ThemeMode.system pro sledování systémových nastavení uživatele.
Příklad 1 — globální nastavení motivu přes MaterialApp s použitím ColorScheme.fromSeed.
final ThemeData appTheme = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
brightness: Brightness.light,
),
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
cardTheme: const CardTheme(
elevation: 2,
margin: EdgeInsets.all(8),
),
);
return MaterialApp(
theme: appTheme,
themeMode: ThemeMode.system,
home: const MyHomePage(),
);
V tomto příkladu je vytvořen ThemeData s Material 3, barevným schématem založeným na indigo a vlastními styly AppBar a Card. useMaterial3 aktivuje nový systém motivů Material 3 a ColorScheme.fromSeed generuje kompletní paletu.
Příklad 2 — přístup k motivu a přepsání pro část aplikace.
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Column(
children: [
Text(
'Standardní nadpis',
style: theme.textTheme.headlineMedium,
),
Theme(
data: theme.copyWith(
colorScheme: theme.colorScheme.copyWith(
primary: Colors.orange,
),
),
child: const SpecialSection(),
),
],
);
}
Druhý příklad ukazuje použití Theme.of(context) pro čtení stylů a Theme() s copyWith pro přepsání motivu v části stromu bez změny globální konfigurace. SpecialSection uvnitř Theme získá oranžovou primární barvu, zbytek aplikace si ponechá původní indigo.
Závěr: globální motiv se nastavuje v MaterialApp, přístup přes Theme.of(context), přepsání přes Theme s copyWith. Pro Material 3 používejte ColorScheme.fromSeed.
Chyba 1: použití primarySwatch místo ColorScheme v Material 3. primarySwatch je zastaralý a není podporován v Material 3. Při použití useMaterial3: true s primarySwatch Flutter zobrazí varování. Řešení: přejít na ColorScheme.fromSeed pro generování palety.
Chyba 2: pevné nastavení barev ve widgetech místo použití Theme.of(context). Vývojáři píší Colors.blue přímo do Containeru místo primární nebo sekundární barvy z motivu. Při změně motivu tyto barvy zůstávají nezměněné, což narušuje jednotný styl. Řešení: vždy používejte Theme.of(context).colorScheme.primary nebo jiné barvy z motivu.
Chyba 3: absence darkTheme. Pokud aplikace nedefinuje darkTheme, při zapnutí tmavého motivu na zařízení se Flutter pokouší automaticky přizpůsobit světlý motiv, což často dává nekvalitní výsledek. Řešení: vždy předávejte darkTheme v MaterialApp, i když tmavý motiv není prioritou — to je důležité UX pro uživatele.
Chyba 4: vytváření nového motivu při každém build. Pokud je ThemeData vytvářeno uvnitř build metody, každé přestavění widgetu vytváří nový objekt motivu, čímž se narušuje optimalizace InheritedWidget. Řešení: přesuňte ThemeData do statického pole nebo const konstruktoru mimo build.
Závěr: správná motivace vyžaduje jednotný centralizovaný přístup. Přesuňte ThemeData do konstant, používejte barevná schémata z motivu a vždy definujte oba motivy — světlý i tmavý.
Často kladené otázky
ThemeData — konfigurační data (barvy, písma, styly). Theme — InheritedWidget, který předává ThemeData dolů stromem widgetů. Theme.of(context) vrací ThemeData, který nejbližší Theme šíří v aktuálním kontextu.
Spravujte themeMode v MaterialApp prostřednictvím stavu aplikace. Změňte stav z ThemeMode.light na ThemeMode.dark a Flutter přestaví celý strom s novým motivem. Pro plynulou animaci použijte AnimatedTheme.
ColorScheme.fromSeed — metoda Material 3, která přijímá jednu základní barvu (seedColor) a generuje úplnou harmonickou paletu: primary, secondary, tertiary, surface, error a jejich on-varianty. Umožňuje získat konzistentní barevné schéma z jedné barvy značky.
Prostřednictvím TextTheme uvnitř ThemeData: zadejte TextStyle s fontFamily pro každou úroveň. Pro Google Fonts použijte balíček google_fonts, předávající fontFamily přímo do TextTheme. Pro lokální písma — připojte je přes pubspec.yaml v sekci fonts.
Ano. Zabalte obrazovku do Theme s přepsanými daty přes copyWith. Všechny podřízené widgety uvnitř tohoto Theme získají změněné styly, zatímco zbytek aplikace si ponechá původní motiv. To nevytváří žádnou režii.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také