8 Widget Flutter untuk Pemula
Bikin aplikasi Color Match Outfit dari nol — lengkap dengan penjelasan, kode siap pakai, dan preview tampilan.
🛠Persiapan Awal
Sebelum mulai, pastikan Flutter sudah terpasang di komputer kamu. Jalankan perintah berikut di terminal:
# 1. Buat project baru flutter create color_match_outfit cd color_match_outfit # 2. Jalankan aplikasi flutter run
Struktur Folder yang Disarankan
Konfigurasi pubspec.yaml (untuk Materi 2)
flutter:
uses-material-design: true
assets:
- assets/images/
pubspec.yaml, jalankan flutter pub get dan restart aplikasi agar asset dikenali.
1Text Widget
📚 Penjelasan
Widget Text menampilkan teks. Tampilannya diatur lewat TextStyle.
| Properti | Fungsi | Contoh |
|---|---|---|
fontSize | Ukuran huruf | 24 |
color | Warna teks | Colors.white |
fontWeight | Ketebalan | FontWeight.bold |
fontStyle | Miring / normal | FontStyle.italic |
letterSpacing | Jarak antar huruf | 1.5 |
textAlign | Perataan teks | TextAlign.center |
💻 Kode Lengkap
import 'package:flutter/material.dart'; class Materi1Page extends StatelessWidget { const Materi1Page({super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5EFE6), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: const [ Text( 'Color Match Outfit', style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: Color(0xFF6B4F3B), letterSpacing: 1.2, ), textAlign: TextAlign.center, ), SizedBox(height: 12), Text( 'Temukan paduan warna pakaian\nterbaik untukmu!', style: TextStyle( fontSize: 16, color: Colors.brown, fontStyle: FontStyle.italic, ), textAlign: TextAlign.center, ), ], ), ), ); } }
Buat tampilan judul aplikasi Color Match Outfit dengan tulisan dan deskripsi (contoh di atas).
2Image Widget
📚 Penjelasan
| Properti | Fungsi |
|---|---|
Image.asset('path') | Ambil gambar dari folder project |
width / height | Ukuran gambar (px) |
fit: BoxFit.cover | Isi area tanpa distorsi (crop) |
fit: BoxFit.contain | Muat seluruh gambar |
fit: BoxFit.fill | Regangkan (bisa gepeng) |
Langkah Konfigurasi
- Siapkan gambar, misal
outfit1.jpg. - Letakkan di
assets/images/outfit1.jpg. - Daftarkan di
pubspec.yaml. - Jalankan
flutter pub getlalu restart.
💻 Kode Lengkap
import 'package:flutter/material.dart'; class Materi2Page extends StatelessWidget { const Materi2Page({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Galeri Outfit')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ClipRRect( borderRadius: BorderRadius.circular(16), child: Image.asset( 'assets/images/outfit1.jpg', width: 250, height: 300, fit: BoxFit.cover, ), ), const SizedBox(height: 16), const Text( 'Outfit Earth Tone', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), ], ), ), ); } }
flutter pub get & restart.
Tampilkan gambar outfit dengan BoxFit.cover (contoh di atas).
3Container Widget
📚 Penjelasan
| Properti | Fungsi |
|---|---|
width / height | Ukuran kotak |
color | Warna latar (jangan dipakai jika ada decoration) |
padding | Jarak isi ke tepi dalam |
margin | Jarak kotak ke elemen luar |
decoration: BoxDecoration() | Border, radius, gradien |
borderRadius | Sudut melengkung |
decoration, jangan pakai color di Container. Taruh warna di dalam BoxDecoration(color: ...).
💻 Kode Lengkap — Pilihan Warna Earth Tone
import 'package:flutter/material.dart'; class Materi3Page extends StatelessWidget { const Materi3Page({super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5EFE6), appBar: AppBar(title: const Text('Pilihan Warna')), body: Center( child: Wrap( spacing: 16, runSpacing: 16, alignment: WrapAlignment.center, children: const [ ColorBox(color: Color(0xFF8B7355), label: 'Taupe'), ColorBox(color: Color(0xFFA67B5B), label: 'Caramel'), ColorBox(color: Color(0xFF6B4F3B), label: 'Brown'), ColorBox(color: Color(0xFFD2B48C), label: 'Tan'), ], ), ), ); } } class ColorBox extends StatelessWidget { final Color color; final String label; const ColorBox({super.key, required this.color, required this.label}); @override Widget build(BuildContext context) { return Container( width: 140, height: 140, margin: const EdgeInsets.all(4), padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(20), boxShadow: const [ BoxShadow(color: Colors.black26, blurRadius: 6, offset: Offset(2, 3)), ], ), child: Center( child: Text( label, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, ), ), ), ); } }
Buat kotak pilihan warna dengan sudut melengkung (contoh di atas).
4Icon Widget
📚 Penjelasan
| Properti | Fungsi |
|---|---|
Icon(Icons.nama) | Menampilkan ikon bawaan |
size | Ukuran ikon |
color | Warna ikon |
Perbedaan Icon vs Image
- Icon → simbol vektor, ringan, ikut berubah warna (
Icons.palette,Icons.colorize). - Image → gambar raster/foto, tidak bisa di-recolor otomatis.
💻 Kode Lengkap — Kumpulan Ikon Color Match
import 'package:flutter/material.dart'; class Materi4Page extends StatelessWidget { const Materi4Page({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Ikon Color Match')), body: Center( child: Wrap( spacing: 30, runSpacing: 30, alignment: WrapAlignment.center, children: const [ IconItem(icon: Icons.palette, label: 'Palette'), IconItem(icon: Icons.colorize, label: 'Colorize'), IconItem(icon: Icons.checkroom, label: 'Outfit'), IconItem(icon: Icons.brush, label: 'Brush'), IconItem(icon: Icons.gradient, label: 'Gradient'), IconItem(icon: Icons.auto_awesome, label: 'Generate'), ], ), ), ); } } class IconItem extends StatelessWidget { final IconData icon; final String label; const IconItem({super.key, required this.icon, required this.label}); @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 48, color: const Color(0xFF6B4F3B)), const SizedBox(height: 6), Text(label, style: const TextStyle(fontSize: 12)), ], ); } }
Buat kumpulan ikon sesuai aplikasi Color Match (contoh di atas).
5Button Widget
onPressed.
📚 Penjelasan
| Jenis | Karakteristik |
|---|---|
ElevatedButton | Latar penuh (paling menonjol) |
OutlinedButton | Bergaris tepi (sekunder) |
TextButton | Tanpa latar (tersier) |
Semua punya onPressed → fungsi yang dijalankan saat ditekan. Jika null → tombol nonaktif.
💻 Kode Lengkap — Tombol "Generate Warna"
import 'package:flutter/material.dart'; class Materi5Page extends StatefulWidget { const Materi5Page({super.key}); @override State<Materi5Page> createState() => _Materi5PageState(); } class _Materi5PageState extends State<Materi5Page> { String hasilWarna = 'Belum ada warna'; Color warnaTampil = const Color(0xFFD2B48C); void generateWarna() { final warna = [ [const Color(0xFF8B7355), 'Taupe'], [const Color(0xFFA67B5B), 'Caramel'], [const Color(0xFF6B4F3B), 'Brown'], [const Color(0xFFD2B48C), 'Tan'], [const Color(0xFFCD853F), 'Peru'], ]; final pilihan = (warna..shuffle()).first; setState(() { warnaTampil = pilihan[0] as Color; hasilWarna = pilihan[1] as String; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Generate Warna')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 160, height: 160, decoration: BoxDecoration( color: warnaTampil, borderRadius: BorderRadius.circular(20), ), ), const SizedBox(height: 20), Text( hasilWarna, style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold), ), const SizedBox(height: 30), ElevatedButton.icon( onPressed: generateWarna, icon: const Icon(Icons.colorize), label: const Text('Generate Warna'), ), const SizedBox(height: 12), OutlinedButton( onPressed: () { setState(() { hasilWarna = 'Belum ada warna'; warnaTampil = const Color(0xFFD2B48C); }); }, child: const Text('Reset'), ), const SizedBox(height: 12), TextButton( onPressed: () => ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Color Match Outfit v1.0')), ), child: const Text('Tentang Aplikasi'), ), ], ), ), ); } }
Buat tombol Generate Warna yang menampilkan respons saat diklik (contoh di atas).
6Card Widget
📚 Penjelasan
| Properti | Fungsi |
|---|---|
elevation | Bayangan (semakin besar semakin "naik") |
child | Isi kartu |
shape | Bentuk (misal sudut melengkung) |
margin | Jarak luar kartu |
💻 Kode Lengkap — Kartu Rekomendasi Earth Tone
import 'package:flutter/material.dart'; class Materi6Page extends StatelessWidget { const Materi6Page({super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5EFE6), appBar: AppBar(title: const Text('Rekomendasi Warna')), body: ListView( padding: const EdgeInsets.all(16), children: const [ RekomendasiCard( warna: Color(0xFF8B7355), judul: 'Taupe', deskripsi: 'Cocok untuk kemeja formal, terkesan elegan.', icon: Icons.checkroom, ), RekomendasiCard( warna: Color(0xFFA67B5B), judul: 'Caramel', deskripsi: 'Hangat dan nyaman untuk outfit casual.', icon: Icons.brush, ), RekomendasiCard( warna: Color(0xFF6B4F3B), judul: 'Brown', deskripsi: 'Netral dan mudah dipadukan dengan warna lain.', icon: Icons.palette, ), ], ), ); } } class RekomendasiCard extends StatelessWidget { final Color warna; final String judul; final String deskripsi; final IconData icon; const RekomendasiCard({ super.key, required this.warna, required this.judul, required this.deskripsi, required this.icon, }); @override Widget build(BuildContext context) { return Card( elevation: 4, margin: const EdgeInsets.only(bottom: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Container( width: 60, height: 60, decoration: BoxDecoration( color: warna, borderRadius: BorderRadius.circular(12), ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, size: 18, color: warna), const SizedBox(width: 6), Text( judul, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ], ), const SizedBox(height: 6), Text(deskripsi, style: const TextStyle(fontSize: 14)), ], ), ), ], ), ), ); } }
Buat kartu rekomendasi warna pakaian bertema Earth Tone (contoh di atas).
7Scaffold Widget
📚 Penjelasan
| Bagian | Fungsi |
|---|---|
appBar | Bar atas (judul, tombol) |
body | Isi utama halaman |
floatingActionButton | Tombol melayang di kanan bawah |
drawer | Menu samping (opsional) |
bottomNavigationBar | Navigasi bawah (opsional) |
Hubungan Scaffold & MaterialApp
MaterialApp = rumah besar aplikasi (tema, routing). Scaffold = kerangka per halaman di dalam rumah tersebut. Setiap halaman butuh Scaffold; MaterialApp cukup satu di root.
💻 Kode Lengkap — Kerangka Halaman Utama
import 'package:flutter/material.dart'; class Materi7Page extends StatelessWidget { const Materi7Page({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Color Match Outfit'), backgroundColor: const Color(0xFF6B4F3B), foregroundColor: Colors.white, ), body: const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.palette, size: 80, color: Color(0xFFA67B5B)), SizedBox(height: 16), Text( 'Selamat Datang!', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), SizedBox(height: 8), Text( 'Temukan paduan warna outfit terbaikmu.', textAlign: TextAlign.center, style: TextStyle(fontSize: 14), ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: () { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Fitur segera hadir!')), ); }, backgroundColor: const Color(0xFF6B4F3B), child: const Icon(Icons.add, color: Colors.white), ), ); } }
Buat kerangka halaman utama aplikasi Color Match (contoh di atas).
8SafeArea Widget
📚 Penjelasan
SafeArea = bantalan otomatis agar konten tidak menabrak:
- Status bar (jam, baterai di atas)
- Notch / punch-hole (kamera depan)
- Area navigasi bawah (gesture bar)
Hubungan SafeArea & Scaffold
Scaffold belum tentu memberi jarak aman, terutama body. SafeArea membungkus body supaya aman di semua perangkat.
💻 Kode Lengkap
import 'package:flutter/material.dart'; class Materi8Page extends StatelessWidget { const Materi8Page({super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5EFE6), body: SafeArea( child: Column( children: [ Container( width: double.infinity, padding: const EdgeInsets.all(20), color: const Color(0xFF6B4F3B), child: const Text( 'Color Match Outfit', textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold, ), ), ), Expanded( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: const [ Icon(Icons.shield, size: 60, color: Color(0xFFA67B5B)), SizedBox(height: 12), Text( 'Konten aman dari notch & status bar', textAlign: TextAlign.center, style: TextStyle(fontSize: 16), ), ], ), ), ), Container( width: double.infinity, padding: const EdgeInsets.all(16), color: const Color(0xFFD2B48C), child: const Text( '© 2024 Color Match', textAlign: TextAlign.center, style: TextStyle(color: Colors.white), ), ), ], ), ), ); } }
Buat tampilan aplikasi yang kontennya tidak tertutup notch atau status bar (contoh di atas).
🏆Proyek Gabungan: Semua dalam Satu Aplikasi
Gabungkan 8 materi jadi satu aplikasi utuh. Ini adalah contoh main.dart final:
import 'package:flutter/material.dart'; void main() => runApp(const ColorMatchApp()); class ColorMatchApp extends StatelessWidget { const ColorMatchApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Color Match Outfit', debugShowCheckedModeBanner: false, theme: ThemeData(primarySwatch: Colors.brown), home: const HomePage(), ); } } class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5EFE6), appBar: AppBar( // Materi 7 title: const Text('Color Match Outfit'), backgroundColor: const Color(0xFF6B4F3B), foregroundColor: Colors.white, ), body: SafeArea( // Materi 8 child: ListView( padding: const EdgeInsets.all(16), children: [ // Materi 1: Text judul const Text( 'Temukan Warna Outfitmu', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFF6B4F3B), ), ), const SizedBox(height: 8), const Text('Pilih warna yang cocok untuk gayamu hari ini.'), const SizedBox(height: 16), // Materi 2: Image ClipRRect( borderRadius: BorderRadius.circular(16), child: Image.asset( 'assets/images/outfit1.jpg', height: 200, width: double.infinity, fit: BoxFit.cover, errorBuilder: (_, __, ___) => Container( height: 200, color: Colors.brown.shade200, child: const Center(child: Icon(Icons.image, size: 60)), ), ), ), const SizedBox(height: 20), // Materi 3: Container pilihan warna const Text('Pilihan Warna Earth Tone:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Wrap( spacing: 12, runSpacing: 12, children: const [ _MiniColorBox(color: Color(0xFF8B7355)), _MiniColorBox(color: Color(0xFFA67B5B)), _MiniColorBox(color: Color(0xFF6B4F3B)), _MiniColorBox(color: Color(0xFFD2B48C)), ], ), const SizedBox(height: 20), // Materi 4: Icon const Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Icon(Icons.palette, size: 40, color: Color(0xFF6B4F3B)), Icon(Icons.colorize, size: 40, color: Color(0xFF6B4F3B)), Icon(Icons.checkroom, size: 40, color: Color(0xFF6B4F3B)), Icon(Icons.brush, size: 40, color: Color(0xFF6B4F3B)), ], ), const SizedBox(height: 20), // Materi 6: Card Card( elevation: 4, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: const Padding( padding: EdgeInsets.all(16), child: Row( children: [ Icon(Icons.auto_awesome, color: Color(0xFFA67B5B)), SizedBox(width: 12), Expanded( child: Text( 'Kombinasi caramel + tan cocok untuk acara santai.', style: TextStyle(fontSize: 14), ), ), ], ), ), ), const SizedBox(height: 20), // Materi 5: Button ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF6B4F3B), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 14), ), onPressed: () { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Warna berhasil di-generate!')), ); }, icon: const Icon(Icons.colorize), label: const Text('Generate Warna'), ), ], ), ), ); } } class _MiniColorBox extends StatelessWidget { final Color color; const _MiniColorBox({required this.color}); @override Widget build(BuildContext context) { return Container( width: 60, height: 60, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(12), ), ); } }
📋Rangkuman Cepat
TextStyleBoxFitBoxDecorationIcons.paletteonPressedelevationAppBar💡Tips Belajar untuk Pemula
- Ubah satu properti, lihat hasilnya. Coba ganti
fontSize32 → 40, lihat perubahannya. - Hot Reload. Tekan
rdi terminal untuk melihat perubahan tanpa restart. - Baca error dengan teliti. Flutter memberi pesan error yang jelas (baris & penyebab).
- Gunakan
constdi widget yang tidak berubah untuk performa lebih baik. - Konsisten urutan. Kerjakan materi 1 → 8 berurutan, karena setiap materi saling membangun.
