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) фреймворк поднимается вверх по дереву до первого 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 для настройки скорости анимации.
Вывод: dark theme реализуется через 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(
'Standard headline',
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, даже если dark theme не является приоритетом — это важный 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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также