Theme и ThemeData — централните механизми за тематизация във Flutter, които позволяват глобално задаване на цветове, шрифтове, разстояния и стилове на компоненти за цялото приложение. ThemeData е конфигурационен обект, който се предава на MaterialApp чрез параметъра theme. Според официалната документация на Flutter (2026), правилната настройка на ThemeData намалява количеството дублиран код за стилизиране със 70–80% и осигурява единообразен външен вид на екраните. Вградената система за наследяване позволява предефиниране на темата на ниво отделни уиджети чрез Theme.of(context).
Основни точки
ThemeData — клас, съдържащ пълно описание на визуалния стил на Material приложение. Предава се на MaterialApp чрез параметъра theme или darkTheme и се наследява от всички дъщерни уиджети. Всеки Material Design уиджет използва ThemeData за получаване на своите стилове: цветове на бутони, размери на AppBar, стилове на текст, разстояния на карти и икони.
В основата на ThemeData стои ColorScheme, който дефинира primary, secondary, surface, error и други цветове. От тези цветове автоматично се изчисляват състоянията (hover, focus, pressed) за всички Material компоненти. Например ElevatedButton използва primary цвят за фон и onPrimary за текст — без допълнителна конфигурация.
Уиджетът Theme — е InheritedWidget, който разпространява темата надолу по дървото от уиджети. Всеки уиджет може да получи текущата тема чрез Theme.of(context), както и да създаде нова тема на базата на съществуваща с предефинирани стойности чрез Theme.copyWith или ThemeData.copyWith.
Извод: ThemeData — единният източник на стилове за приложението. Започнете разработката с дефиниране на ThemeData — това задава визуалния език на целия проект и предотвратява разпръснати стилове на различни екрани.
ColorScheme — централният елемент на тематизация в Material 3. Той заменя остарелите primarySwatch и primaryColor, предоставяйки пълен набор от цветове за всички състояния и компоненти.
ColorScheme съдържа 12 основни цвята: primary, onPrimary, secondary, onSecondary, surface, onSurface, error, onError, background, onBackground, outline и shadow. За всеки цвят автоматично се изчисляват light и dark варианти, както и цветове за състоянията hover, focus, pressed и dragged. При задаване само на primary, framework автоматично генерира останалите цветове чрез ColorScheme.fromSeed.
Методът ColorScheme.fromSeed (Material 3) приема базов цвят seedColor и генерира пълна хармонична палитра на базата на алгоритъма Material Design 3. Това елиминира ръчния подбор на complementary и analogous цветове. Достатъчно е да предадете един основен цвят на марката и ColorScheme.fromSeed ще създаде съгласувана палитра за цялата Material система.
Извод: в нови проекти използвайте ColorScheme.fromSeed за генериране на палитра. За съвместимост с Material 2 — primarySwatch. ColorScheme е задължителният минимум за Material 3.
TextTheme — част от ThemeData, която дефинира стиловете на текста за всички нива на заглавия, подзаглавия, body и етикети. Material Design дефинира 15 текстови стила: headlineLarge, headlineMedium, headlineSmall, titleLarge, titleMedium и други.
Типографията се задава или чрез GoogleFonts за автоматично зареждане на шрифтове, или чрез вградения Theme.of(context).textTheme с персонализирани TextStyle. GoogleFonts предоставя стотици шрифтове чрез пакета google_fonts, който ги кешира локално след първото зареждане. Алтернатива — вграждане на шрифтове в assets на проекта чрез pubspec.yaml.
За адаптивна типография TextTheme поддържа MediaQuery.textScaleFactor — при увеличаване на системния шрифт всички текстови стилове се мащабират пропорционално. Допълнително могат да се зададат различни размери на шрифта за различни форм-фактори чрез isTest в зависимост от MediaQuery.size.width.
Извод: дефинирайте TextTheme в ThemeData и използвайте Theme.of(context).textTheme за всички текстови елементи. Това осигурява единообразие на шрифтовете и опростява глобалните промени в типографията.
Theme — InheritedWidget, който разпространява темата от родител към деца. Всеки дъщерен уиджет може както да чете текущата тема чрез Theme.of(context), така и да създаде свое копие с промени чрез ThemeData.copyWith.
Механизъм на наследяване: ако уиджет е обвит в Theme с нови данни, всички негови потомци виждат предефинираната тема, а уиджетите извън тази обвивка — оригиналната. Това позволява например изолиране на стилове за конкретен екран: заглавието използва персонализирана тема с променен AppBarTheme, а останалата част от приложението — стандартна.
Влагаността на Theme може да бъде неограничена. Flutter използва йерархично търсене: при извикване на Theme.of(context) framework се изкачва нагоре по дървото до първия Theme и връща неговата тема. Ако не бъде намерен Theme — се хвърля изключение. Затова MaterialApp винаги обвива приложението в Theme.
Извод: наследяването на Theme — гъвкав механизъм за изолиране на стилове. Използвайте предефиниране на тема за отделни екрани без дублиране на общата конфигурация.
Dark theme — вградената възможност на Flutter за превключване между светла и тъмна тема. ThemeData се съхранява в параметрите theme (светла) и darkTheme (тъмна) на MaterialApp. Параметърът themeMode управлява режима: ThemeMode.light (винаги светла), ThemeMode.dark (винаги тъмна) или ThemeMode.system (следва системните настройки).
При имплементиране на тъмна тема не е необходимо да създавате всички стилове наново. Достатъчно е да предадете ColorScheme.fromSeed(seedColor, brightness: Brightness.dark) в darkTheme. Framework автоматично коригира цветовете за тъмен фон: surface става тъмносиво, текстът — светъл. Останалите подтеми (AppBarTheme, CardTheme, BottomNavigationBarTheme) се наследяват от светлата версия, ако не са изрично предефинирани.
За плавен преход между темите Flutter предоставя анимация чрез AnimatedTheme. При смяна на themeMode цветовете и стиловете се анимират, създавайки визуално приятно превключване. AnimatedTheme използва Duration и Curve за настройка на скоростта на анимация.
Извод: тъмната тема се имплементира чрез darkTheme и ColorScheme.fromSeed с brightness: Brightness.dark. Използвайте ThemeMode.system за следване на системните настройки на потребителя.
Пример 1 — глобална настройка на тема чрез MaterialApp с използване на 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(),
);
В този пример се създава ThemeData с Material 3, цветова схема на базата на indigo и персонализирани стилове на AppBar и Card. useMaterial3 активира новата система за теми Material 3, а ColorScheme.fromSeed генерира пълната палитра.
Пример 2 — достъп до темата и предефиниране за част от приложението.
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Column(
children: [
Text(
'Стандартно заглавие',
style: theme.textTheme.headlineMedium,
),
Theme(
data: theme.copyWith(
colorScheme: theme.colorScheme.copyWith(
primary: Colors.orange,
),
),
child: const SpecialSection(),
),
],
);
}
Вторият пример показва използването на Theme.of(context) за четене на стилове и Theme() с copyWith за предефиниране на темата в част от дървото без промяна на глобалната конфигурация. SpecialSection вътре в Theme ще получи оранжев primary цвят, останалата част от приложението запазва оригиналния indigo.
Извод: глобалната тема се задава в MaterialApp, достъп чрез Theme.of(context), предефиниране чрез Theme с copyWith. За Material 3 използвайте ColorScheme.fromSeed.
Грешка 1: използване на primarySwatch вместо ColorScheme в Material 3. primarySwatch е остарял и не се поддържа в Material 3. При използване на useMaterial3: true с primarySwatch Flutter издава предупреждение. Решение: преминете на ColorScheme.fromSeed за генериране на палитра.
Грешка 2: твърдо задаване на цветове в уиджети вместо използване на Theme.of(context). Разработчиците пишат Colors.blue директно в Container, вместо primary или secondary цвят от темата. При смяна на темата такива цветове остават непроменени, нарушавайки единния стил. Решение: винаги използвайте Theme.of(context).colorScheme.primary или други цветове от темата.
Грешка 3: липса на darkTheme. Ако приложението не дефинира darkTheme, при включване на тъмна тема на устройството Flutter се опитва автоматично да адаптира светлата тема, което често дава некачествен резултат. Решение: винаги предавайте darkTheme в MaterialApp, дори ако тъмната тема не е приоритет — това е важен UX за потребителите.
Грешка 4: създаване на нова тема при всяко build. Ако ThemeData се създава вътре в build метода, всяко преизграждане на уиджета създава нов обект на тема, нарушавайки оптимизацията на InheritedWidget. Решение: изнесете ThemeData в статично поле или const конструктор извън build.
Извод: правилната тематизация изисква единен централизиран подход. Изнесете ThemeData в константи, използвайте цветови схеми от темата и винаги дефинирайте и двете теми — светла и тъмна.
Често задавани въпроси
ThemeData — конфигурационни данни (цветове, шрифтове, стилове). Theme — InheritedWidget, който предава ThemeData надолу по дървото от уиджети. Theme.of(context) връща ThemeData, който най-близкият Theme разпространява в текущия контекст.
Управлявайте themeMode в MaterialApp чрез състоянието на приложението. Променете състоянието от ThemeMode.light на ThemeMode.dark и Flutter ще преизгради цялото дърво с новата тема. За плавна анимация използвайте AnimatedTheme.
ColorScheme.fromSeed — метод на Material 3, който приема един базов цвят (seedColor) и генерира пълна хармонична палитра: primary, secondary, tertiary, surface, error и техните on-варианти. Позволява получаване на съгласувана цветова схема от един цвят на марката.
Чрез TextTheme вътре в ThemeData: посочете TextStyle с fontFamily за всяко ниво. За Google Fonts използвайте пакета google_fonts, предавайки fontFamily директно в TextTheme. За локални шрифтове — свържете ги чрез pubspec.yaml в секцията fonts.
Да. Обвийте екрана в Theme с предефинирани данни чрез copyWith. Всички дъщерни уиджети вътре в този Theme ще получат променените стилове, а останалата част от приложението ще запази оригиналната тема. Това не създава допълнително натоварване.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също