Theme и ThemeData — шта је то, принципи и подешавање стилова

Аутор: IT Sectr Објављено: 2026-07-03 Време читања: 8 мин

Theme и ThemeData — централни механизми темизације у Flutter-у, који омогућавају глобално постављање боја, фонтова, размака и стилова компоненти за целу апликацију. ThemeData — конфигурациони објекат који се прослеђује MaterialApp-у кроз параметар theme. Према званичној документацији Flutter-а (2026), правилно подешавање ThemeData смањује количину дуплираног кода за стилизовање за 70–80% и обезбеђује једнообразан изглед екрана. Уграђени систем наслеђивања омогућава преиначење теме на нивоу појединачних виџета кроз Theme.of(context).

Главно

  • ThemeData — конфигурациони објекат са палетом боја, типографијом и стиловима компоненти
  • Theme.of(context) — приступ тренутној теми из било ког виџета кроз BuildContext
  • Light/Dark — уграђена подршка за светлу и тамну тему кроз theme и darkTheme
  • Theme — виџет који наслеђује тему потомцима и омогућава њено преиначење
  • ColorScheme — скуп хармоничних боја који генерише стилове за цео Material систем

Шта су Theme и ThemeData

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: основа палете боја

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.

Typography и TextTheme: фонтови апликације

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: тамна тема апликације

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 за праћење системских подешавања корисника.

Примери кода са Theme и ThemeData

Пример 1 — глобално подешавање теме кроз MaterialApp коришћењем ColorScheme.fromSeed.

dart
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 — приступ теми и преиначење за део апликације.

dart
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 у константе, користите шеме боја из теме и увек дефинишите обе теме — светлу и тамну.

Често постављана питања

Чиме се разликује Theme од ThemeData?

ThemeData — то су конфигурациони подаци (боје, фонтови, стилови). Theme — InheritedWidget који прослеђује ThemeData низ дрво виџета. Theme.of(context) враћа ThemeData који најближи Theme шири у тренутном контексту.

Како динамички пребацити тему апликације?

Управљајте themeMode-ом у MaterialApp-у кроз стање апликације. Промените стање са ThemeMode.light на ThemeMode.dark, и Flutter ће поново изградити цело стабло са новом темом. За глатку анимацију користите AnimatedTheme.

Шта је ColorScheme.fromSeed?

ColorScheme.fromSeed — метод Material 3 који прима једну основну боју (seedColor) и генерише потпуну хармоничну палету: primary, secondary, tertiary, surface, error и њихове on-варијанте. Омогућава добијање усклађене шеме боја из једне боје бренда.

Како користити прилагођене фонтове са Theme-ом?

Кроз TextTheme унутар ThemeData: наведите TextStyle са fontFamily за сваки ниво. За Google Fonts користите пакет google_fonts, прослеђујући fontFamily директно у TextTheme. За локалне фонтове — повежите их кроз pubspec.yaml у секцији fonts.

Може ли се преиначити тема за један екран?

Да. Умотајте екран у Theme са преиначеним подацима кроз copyWith. Сви потомци унутар овог Theme-а ће добити измењене стилове, а остатак апликације ће задржати оригиналну тему. Ово не ствара додатне трошкове.

Закључак

  • ThemeData — конфигурациони објекат са палетом боја, типографијом и стиловима свих Material компоненти
  • ColorScheme.fromSeed — главни начин генерисања палете боја у Material 3 из једне боје бренда
  • Theme.of(context) — приступ тренутној теми за читање стилова без дуплирања кода
  • Theme — InheritedWidget за наслеђивање и преиначење теме у подстаблу виџета
  • Dark theme — засебан ThemeData са brightness: Brightness.dark, управљан кроз themeMode
  • Препорука: извуците ThemeData у static или const, увек постављајте theme и darkTheme у MaterialApp

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође