Theme و ThemeData — چیست، اصول و تنظیم استایل‌ها

نویسنده: IT Sectr منتشر شده: 2026-07-03 زمان مطالعه: 8 دقیقه

Theme و ThemeData — مکانیسم‌های مرکزی تم‌سازی در Flutter هستند که امکان تنظیم رنگ‌ها، فونت‌ها، فاصله‌ها و استایل‌های کامپوننت‌ها را به صورت سراسری برای کل برنامه فراهم می‌کنند. ThemeData یک شیء پیکربندی است که از طریق پارامتر theme به MaterialApp ارسال می‌شود. طبق مستندات رسمی Flutter (2026)، پیکربندی صحیح ThemeData مقدار کد تکراری استایل‌دهی را ۷۰–۸۰٪ کاهش می‌دهد و ظاهر یکپارچه‌ای برای صفحه‌ها تضمین می‌کند. سیستم داخلی وراثت امکان بازتعریف تم را در سطح ویجت‌های جداگانه از طریق Theme.of(context) فراهم می‌کند.

نکات مهم

  • ThemeData — شیء پیکربندی با پالت رنگی، تایپوگرافی و استایل‌های کامپوننت‌ها
  • Theme.of(context) — دسترسی به تم فعلی از هر ویجتی از طریق BuildContext
  • روشن/تاریک — پشتیبانی داخلی از تم روشن و تاریک از طریق theme و darkTheme
  • Theme — ویجتی که تم را به عناصر فرزند به ارث می‌دهد و امکان بازتعریف آن را فراهم می‌کند
  • ColorScheme — مجموعه‌ای از رنگ‌های هماهنگ که استایل‌هایی برای کل سیستم Material تولید می‌کند

Theme و ThemeData چیست

ThemeData — کلاسی است که توصیف کامل استایل بصری برنامه Material را شامل می‌شود. از طریق پارامتر theme یا darkTheme به MaterialApp ارسال شده و به تمام ویجت‌های فرزند به ارث می‌رسد. هر ویجت 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 شامل ۱۲ رنگ اصلی است: primary، onPrimary، secondary، onSecondary، surface، onSurface، error، onError، background، onBackground، outline و shadow. برای هر رنگ، انواع light و dark به همراه رنگ‌های حالت‌های hover، focus، pressed و dragged به صورت خودکار محاسبه می‌شوند. هنگام تعیین فقط primary، فریم‌ورک بقیه رنگ‌ها را به صورت خودکار از طریق 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 است که استایل‌های متن را برای تمام سطوح عنوان‌ها، زیرعنوان‌ها، بدنه و برچسب‌ها تعریف می‌کند. Material Design ۱۵ استایل متنی را تعریف می‌کند: 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 — مکانیسمی انعطاف‌پذیر برای جداسازی استایل‌ها است. از بازتعریف تم برای صفحه‌های جداگانه بدون تکرار پیکربندی کلی استفاده کنید.

تم تاریک: تم تیره برنامه

تم تاریک — قابلیت داخلی Flutter برای جابجایی بین تم روشن و تاریک است. ThemeData در پارامترهای theme (روشن) و darkTheme (تاریک) MaterialApp ذخیره می‌شود. پارامتر themeMode حالت را مدیریت می‌کند: ThemeMode.light (همیشه روشن)، ThemeMode.dark (همیشه تاریک) یا ThemeMode.system (پیروی از تنظیمات سیستم).

هنگام پیاده‌سازی تم تاریک نیازی به ایجاد تمام استایل‌ها از نو نیست. کافی است ColorScheme.fromSeed(seedColor, brightness: Brightness.dark) را در darkTheme ارسال کنید. فریم‌ورک به صورت خودکار رنگ‌ها را برای پس‌زمینه تاریک تصحیح می‌کند: surface خاکستری تیره می‌شود، متن — روشن. زیرتم‌های دیگر (AppBarTheme، CardTheme، BottomNavigationBarTheme) از نسخه روشن به ارث می‌برند، مگر اینکه صریحاً بازتعریف شده باشند.

برای انتقال نرم بین تم‌ها، Flutter انیمیشن را از طریق AnimatedTheme ارائه می‌دهد. هنگام تغییر themeMode، رنگ‌ها و استایل‌ها انیمیشن می‌شوند و یک جابجایی بصری دلپذیر ایجاد می‌کنند. AnimatedTheme از Duration و Curve برای تنظیم سرعت انیمیشن استفاده می‌کند.

نتیجه: تم تاریک از طریق darkTheme و ColorScheme.fromSeed با brightness: Brightness.dark پیاده‌سازی می‌شود. برای پیروی از تنظیمات سیستم کاربر از ThemeMode.system استفاده کنید.

نمونه کد با Theme و ThemeData

مثال ۱ — پیکربندی سراسری تم از طریق 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 پالت کامل را تولید می‌کند.

مثال ۲ — دسترسی به تم و بازتعریف برای بخشی از برنامه.

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 استفاده کنید.

خطاهای رایج در تنظیم تم

خطای ۱: استفاده از primarySwatch به جای ColorScheme در Material 3. primarySwatch منسوخ شده و در Material 3 پشتیبانی نمی‌شود. هنگام استفاده از useMaterial3: true با primarySwatch، Flutter اخطار می‌دهد. راه‌حل: برای تولید پالت به ColorScheme.fromSeed مهاجرت کنید.

خطای ۲: تعیین سخت رنگ‌ها در ویجت‌ها به جای استفاده از Theme.of(context). توسعه‌دهندگان مستقیماً در Container از Colors.blue استفاده می‌کنند به جای رنگ primary یا secondary از تم. هنگام تغییر تم، این رنگ‌ها بدون تغییر می‌مانند و یکپارچگی استایل را نقض می‌کنند. راه‌حل: همیشه از Theme.of(context).colorScheme.primary یا سایر رنگ‌های تم استفاده کنید.

خطای ۳: نبود darkTheme. اگر برنامه darkTheme را تعریف نکند، هنگام فعال‌سازی تم تاریک در دستگاه، Flutter سعی می‌کند تم روشن را به صورت خودکار تطبیق دهد که اغلب نتیجه نامطلوبی به همراه دارد. راه‌حل: همیشه darkTheme را در MaterialApp ارسال کنید، حتی اگر تم تاریک اولویت نباشد — این UX مهمی برای کاربران است.

خطای ۴: ایجاد تم جدید در هر build. اگر ThemeData در داخل متد build ایجاد شود، هر بازسازی ویجت یک شیء تم جدید می‌سازد و بهینه‌سازی InheritedWidget را می‌شکند. راه‌حل: ThemeData را به فیلد استاتیک یا const-سازنده در خارج از build منتقل کنید.

نتیجه: تم‌سازی صحیح نیازمند یک رویکرد متمرکز یکپارچه است. ThemeData را در ثابت‌ها قرار دهید، از طرح‌های رنگی تم استفاده کنید و همیشه هر دو تم — روشن و تاریک را تعریف کنید.

سوالات متداول

تفاوت Theme با ThemeData چیست؟

ThemeData — داده‌های پیکربندی (رنگ‌ها، فونت‌ها، استایل‌ها) است. Theme — InheritedWidgetی است که ThemeData را در پایین درخت ویجت‌ها منتقل می‌کند. Theme.of(context) ThemeDataای را برمی‌گرداند که نزدیک‌ترین Theme در زمینه فعلی منتشر می‌کند.

چگونه تم برنامه را به صورت پویا تغییر دهیم؟

themeMode را در MaterialApp از طریق state برنامه مدیریت کنید. حالت را از 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 برای وراثت و بازتعریف تم در زیردرخت ویجت‌ها
  • تم تاریک — ThemeData جداگانه با brightness: Brightness.dark که از طریق themeMode مدیریت می‌شود
  • توصیه: ThemeData را در static یا const قرار دهید، همیشه theme و darkTheme را در MaterialApp تنظیم کنید

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید