Episode ini menyulap tampilan aplikasi kalian: ThemeData dan material design theming, custom fonts, colors, dan typography, dukungan dark mode dan adaptive UI, serta styling widget dengan decoration dan responsive design.

Aplikasi yang fungsional belum tentu enak dipakai. Episode 7 menutup celah itu: kalian akan belajar membangun identitas visual yang konsisten lewat theming dan styling. Kita membahas ThemeData dan material design theming, custom fonts, colors, dan typography, dukungan dark mode dan adaptive UI, serta styling widget dengan decoration dan responsive design. Setelah episode ini, aplikasi kalian akan terlihat seperti produk sungguhan, bukan demo.
Alih-alih mengatur warna di setiap widget, definisikan tema satu kali di MaterialApp:
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
),
useMaterial3: true,
),
home: const HomeScreen(),
)ColorScheme.fromSeed(seedColor: Colors.indigo) membangkitkan palet warna lengkap dari satu warna benih — pola yang direkomendasikan Material 3. useMaterial3: true mengaktifkan desain token terbaru.
final colorScheme = Theme.of(context).colorScheme;
Container(
color: colorScheme.primary,
child: Text(
'Tombol utama',
style: TextStyle(color: colorScheme.onPrimary),
),
);Theme.of(context).colorScheme mengambil palet aktif. Dengan pola ini, warna tidak pernah di-hardcode di dalam widget — perubahan tema menyebar otomatis ke seluruh aplikasi.
Font custom didaftarkan di pubspec.yaml di bawah blok fonts:
flutter:
fonts:
- family: Poppins
fonts:
- asset: assets/fonts/Poppins-Regular.ttf
- asset: assets/fonts/Poppins-Bold.ttf
weight: 700Setelah font terdaftar di blok flutter.fonts, jalankan flutter pub get lalu pakai keluarga font tersebut.
Definisikan text theme agar tipografi konsisten:
theme: ThemeData(
textTheme: const TextTheme(
headlineMedium: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
),
bodyMedium: TextStyle(
fontSize: 16,
height: 1.5,
),
),
)TextTheme mendefinisikan gaya untuk headlineMedium, bodyMedium, dan seterusnya. Seluruh aplikasi memakai gaya ini tanpa harus menulis ulang TextStyle di setiap tempat.
Sediakan dua tema dan Flutter akan memilih berdasarkan setting sistem:
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
),
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
brightness: Brightness.dark,
),
),
home: const HomeScreen(),
)Dengan theme dan darkTheme terisi, aplikasi menyesuaikan diri dengan mode terang atau gelap perangkat secara otomatis. Brightness.dark membalik palet sehingga tetap kontras.
Untuk keputusan yang bergantung platform, gunakan Theme.of(context).platform atau MediaQuery:
final lebar = MediaQuery.sizeOf(context).width;
if (lebar >= 600) {
return const WideLayout();
}
return const NarrowLayout();MediaQuery.sizeOf(context).width membaca lebar layar saat ini. Pola ini adalah dasar responsive design yang akan dibahas mendalam di episode 18.
BoxDecoration memberi warna gradasi, border, dan bayangan pada Container:
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.indigo, Colors.blue],
),
borderRadius: BorderRadius.circular(12),
boxShadow: const [
BoxShadow(
color: Colors.black26,
blurRadius: 8,
offset: Offset(0, 4),
),
],
),
child: const Text('Kartu bergaya'),
)BoxShadow memberi kedalaman dan BorderRadius.circular(12) membulatkan sudut. double.infinity membuat Container selebar yang diizinkan parent.
Definisikan konstanta spacing di satu tempat agar konsisten:
const double spacingKecil = 8;
const double spacingBesar = 24;
Padding(
padding: EdgeInsets.all(spacingKecil),
child: Text('Elemen dengan jarak konsisten'),
)EdgeInsets.all(spacingKecil) memakai konstanta yang sama di seluruh aplikasi. Konsistensi spacing dan warna adalah ciri aplikasi yang terlihat profesional.
Inti yang harus dibawa pulang:
MaterialApp dengan ColorScheme.fromSeed.Theme.of(context) — jangan hardcode warna di widget.pubspec.yaml dan atur TextTheme terpusat.theme dan darkTheme untuk dukungan dark mode otomatis.BoxDecoration menghidupkan tampilan dengan gradasi, border, dan bayangan.Di episode 8 selanjutnya kita membahas networking dan data handling — HTTP requests dengan package http atau dio, JSON deserialization dengan dart:convert atau json_serializable, async programming dengan Future dan Stream, serta loading states, error handling, dan retry. Aplikasi kalian mulai terhubung ke dunia luar.