themematerial3desainMahir5 mnt baca

ThemeData & Material 3

Tema global: warna, tipografi, dan ColorScheme.

Masalah yang Diselesaikan ThemeData

Di awal project, warna biasanya ditulis langsung di widget: Colors.purple di AppBar, Color(0xFF7C3AED) di tombol, Colors.grey[200] di kartu. Lama-lama ada puluhan varian ungu yang mirip tapi tidak sama, dan saat user minta ganti warna brand, kamu harus berburu satu per satu ke seluruh file. ThemeData menyelesaikan ini dengan satu sumber kebenaran: semua warna, bentuk, dan tipografi didefinisikan sekali di MaterialApp, lalu setiap widget mengambilnya lewat Theme.of(context). Ganti brand berarti edit satu tempat.

Seed Color: Palet Otomatis

Cara termudah membangun tema Material 3 adalah dari satu warna seed. Flutter menurunkan seluruh ColorScheme (primary, secondary, surface, error, dan varian terang/gelapnya) yang harmonis secara otomatis:

dart
MaterialApp(
  theme: ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
    appBarTheme: const AppBarTheme(centerTitle: true),
  ),
  home: const HomePage(),
)

Ini jauh lebih aman daripada meracik tiap warna manual, karena Flutter sudah menghitung kontras yang memenuhi standar aksesibilitas antara teks dan background.

Tema Komponen: Satu Tempat untuk Semua

Untuk aplikasi nyata, kamu ingin tombol, input, dan kartu konsisten tanpa mengulang style di tiap layar. Definisikan di ThemeData:

dart
final temaWarung = ThemeData(
  useMaterial3: true,
  colorScheme: ColorScheme.fromSeed(seedColor: Colors.brown),
  appBarTheme: const AppBarTheme(centerTitle: true),
  elevatedButtonTheme: ElevatedButtonThemeData(
    style: ElevatedButton.styleFrom(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(12),
      ),
      padding: const EdgeInsets.symmetric(vertical: 14, horizontal: 24),
    ),
  ),
  inputDecorationTheme: InputDecorationTheme(
    border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
    filled: true,
  ),
  cardTheme: CardThemeData(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(16),
    ),
    elevation: 2,
  ),
  textTheme: const TextTheme(
    headlineSmall: TextStyle(fontWeight: FontWeight.bold),
  ),
);

Lalu di widget, jangan pernah hardcode. Ambil dari tema:

dart
Container(
  color: Theme.of(context).colorScheme.surfaceContainerHighest,
  child: Text('Total', style: Theme.of(context).textTheme.headlineSmall),
)

Edge Cases yang Perlu Diwaspadai

Pertama, Theme.of(context) hanya bisa dipanggil dari build (atau setelahnya). Memanggilnya di initState akan throw karena widget belum terpasang di tree; kalau butuh tema saat inisialisasi, pindah ke didChangeDependencies. Kedua, dialog dan bottom sheet mewarisi tema dari context yang memanggil showDialog, jadi kalau kamu memanggilnya dari context yang dibungkus Theme kustom, dialog ikut kustom (kadang ini diinginkan, kadang mengejutkan). Ketiga, untuk override lokal satu subtree saja, bungkus dengan widget Theme(data: Theme.of(context).copyWith(...), child: ...), jangan duplikasi seluruh ThemeData. Keempat, ColorScheme.fromSeed dengan brightness: Brightness.dark menghasilkan palet gelap yang berbeda (bukan sekadar versi gelap dari palet terang), jadi selalu definisikan darkTheme terpisah dan uji keduanya.

Kapan TIDAK Mengandalkan ThemeData

Untuk satu layar yang sangat artistik dan sekali pakai (misalnya splash screen ilustrasi atau halaman promo dengan gaya unik), memaksakan semuanya lewat tema global justru bikin ThemeData kotor dengan style yang tidak dipakai di tempat lain. Di kasus itu, style lokal dengan konstanta di file layar tersebut lebih jujur. Juga, widget pihak ketiga yang membawa sistem theming sendiri kadang perlu dibungkus atau di-override secara khusus, jangan dilawan dengan copyWith berlapis-lapis.

Catatan teknis: Theme.of(context) memakai InheritedWidget, jadi widget yang memanggilnya otomatis rebuild saat tema berubah. Inilah alasan dark mode bisa bekerja tanpa mengubah satu pun widget: cukup ganti ThemeData di MaterialApp, seluruh tree ikut diperbarui.

Tantangan

Tema warung

Buat ThemeData dengan seedColor coklat (Colors.brown), AppBar centerTitle true, dan semua ElevatedButton rounded 12. Terapkan di MaterialApp.