Pemrograman Mobile • Flutter / Dart
7
📝
⌨️
📋
🎛️

BAB 7
Form & Input User

Membuat Aplikasi Flutter yang Bisa Berinteraksi dengan Pengguna

Kelas 10 Semester 1 Pemrograman Mobile 22 Slide Interaktif

Gunakan tombol ◀ Sebelumnya / Berikutnya ▶ atau panah keyboard ← →

Roadmap

Peta Materi BAB 7

Inilah perjalanan kita. Setiap "pemberhentian" adalah satu widget input yang akan membuat aplikasimu hidup.

01
TextField
Kotak input teks dasar
02
TextFormField
TextField + validasi
03
Validator
Memeriksa input benar/salah
04
Dropdown
Pilih satu dari daftar
05
Checkbox
Pilihan ya / tidak
06
Radio Button
Pilih satu opsi
07
Date Picker
Memilih tanggal
08
Time Picker
Memilih waktu
09
Form Validation
Validasi seluruh form
10
Mini Project
Form Pendaftaran Siswa
Orientasi

Tujuan Pembelajaran

Setelah BAB ini kamu mampu
  • Membuat kotak input teks dengan TextField
  • Memvalidasi input pengguna dengan Validator
  • Menggunakan Dropdown, Checkbox, dan Radio
  • Menampilkan Date Picker & Time Picker
  • Membangun satu Form lengkap dengan validasi
  • Menyelesaikan Mini Project Form Pendaftaran
Recap BAB 6 — Layout & Responsive

Di BAB 6 kamu sudah belajar menyusun tampilan dengan:

RowColumn ContainerExpanded PaddingMediaQuery

Sekarang tampilan itu akan kita isi dengan input yang bisa diketik & dipilih user. Tata letak (BAB 6) + interaksi (BAB 7) = aplikasi yang nyata.

Mengapa penting?

Tanpa form, aplikasi hanya bisa menampilkan. Dengan form, aplikasi bisa mendengar penggunanya — login, daftar, mengisi survei, mencari produk. Inilah jembatan antara manusia dan aplikasi.

Topik 1 • Point Materi

TextField

TextField adalah widget untuk menerima input teks dari pengguna — seperti kolom nama, email, atau kata sandi.

🏠 Analogi Kehidupan Nyata

🧑‍🎓
📋 Buku Tamu
✍️

Tamu menulis namanya di buku tamu

Penjelasan Analogi

Bayangkan sebuah buku tamu di pintu masuk acara. Setiap tamu menuliskan namanya di baris kosong. TextField adalah baris kosong itu — tempat user "menulis" data ke dalam aplikasimu.

💻 Kode Dart / Flutter

main.dart — TextField dasar
TextField( decoration: InputDecoration( labelText: 'Nama Lengkap', hintText: 'Tulis namamu di sini', border: OutlineInputBorder(), ), onChanged: (value) { print('User mengetik: $value'); }, )

🎬 Demo Visual

Buku Tamu
Topik 1 • Lanjutan

TextField Lanjutan

TextField bisa "dirias" dan "dikendalikan": hint, controller, dan style.

🎛️ TextEditingController

Controller seperti remote TV: kamu bisa membaca isi field dan mengubahnya dari kode kapan saja.

controller + style
final nameCtrl = TextEditingController(); TextField( controller: nameCtrl, obscureText: false, // true = mode password style: TextStyle(color: Colors.white), decoration: InputDecoration( hintText: 'Masukkan email', prefixIcon: Icon(Icons.email), filled: true, ), ) // Membaca isi field kapan saja: print(nameCtrl.text);

🔑 Properti Penting

  • hintText — teks bantuan abu-abu
  • labelText — label yang naik saat fokus
  • prefixIcon — ikon di kiri
  • obscureText — sembunyikan teks (password)
  • keyboardType — jenis keyboard (angka/email)
  • controller — pengendali isi field

🎬 Demo: Mode Password

Login
Topik 2 • Point Materi

TextFormField

TextFormField = TextField + kemampuan validasi. Ia dipakai di dalam sebuah Form.

🏫 Analogi: Formulir Pendaftaran Sekolah

📄
🖊️
🧑‍🏫

Guru memeriksa: "Kolom ini tidak boleh kosong!"

Penjelasan Analogi

TextField biasa = kertas coretan bebas. TextFormField = formulir resmi yang akan diperiksa guru. Jika ada kolom yang salah/kosong, formulir ditolak sampai diperbaiki.

💻 Perbedaan dalam Kode

TextFormField + validator
TextFormField( decoration: InputDecoration( labelText: 'Email', ), validator: (value) { if (value == null || value.isEmpty) { return 'Email tidak boleh kosong'; } return null; // null artinya VALID }, )
TextField

Hanya menerima teks. Tidak tahu apakah benar/salah.

TextFormField

Punya validator & hidup di dalam Form.

Topik 3 • Flowchart Animasi

Validator

Validator adalah satpam input: ia memeriksa data sebelum diterima. Return null = lolos, return teks = pesan error.

🔍 Alur Kerja Validator

User mengetik Input kosong? Ya return 'pesan error' Tidak return null (VALID ✓)

💻 Contoh Validator Email

validator lengkap
validator: (value) { if (value == null || value.isEmpty) { return 'Wajib diisi'; } if (!value.contains('@')) { return 'Email harus mengandung @'; } if (value.length < 5) { return 'Terlalu pendek'; } return null; // semua aturan lolos }
Aturan Emas

return null = data VALID (tidak ada masalah).
return 'teks' = data SALAH, teks tampil sebagai pesan error merah.

Flowchart di kiri "menggambar dirinya sendiri" setiap kali slide ini dibuka.

Topik 4 • Point Materi

Dropdown

DropdownButton membiarkan user memilih satu opsi dari daftar yang muncul ke bawah.

🍔 Analogi: Menu Restoran

📜
🍔
🥤
🧑‍🍳

"Pilih satu menu, ya!"

Penjelasan Analogi

Seperti buku menu restoran: daftarnya tertutup, lalu terbuka saat kamu lihat, dan kamu hanya boleh memilih satu makanan. Itulah cara Dropdown bekerja.

💻 Kode Dropdown

DropdownButton
String? pilihan; final list = ['SMA', 'SMK', 'MA']; DropdownButton<String>( value: pilihan, hint: Text('Pilih jenjang'), items: list.map((j) { return DropdownMenuItem( value: j, child: Text(j), ); }).toList(), onChanged: (val) { setState(() => pilihan = val); }, )

🎬 Demo Interaktif

Pilih Jenjang
Topik 5 • Point Materi

Checkbox

Checkbox adalah pilihan ya / tidak (true / false). Bisa banyak yang dicentang sekaligus.

✅ Analogi: Daftar Belanja

🛒
☑️ Telur
☑️ Roti
⬜ Susu

Centang yang sudah dibeli.

Penjelasan Analogi

Seperti daftar belanja: kamu boleh mencentang beberapa item sekaligus. Setiap kotak punya status sendiri — tercentang (true) atau tidak (false).

💻 Kode Checkbox

CheckboxListTile
bool setuju = false; CheckboxListTile( title: Text('Saya setuju syarat & ketentuan'), value: setuju, onChanged: (val) { setState(() => setuju = val!); }, )

🎬 Demo Interaktif

Persetujuan
Topik 6 • Point Materi

Radio Button

Radio memaksa user memilih hanya satu dari beberapa opsi — sisanya otomatis batal.

📻 Analogi: Tombol Radio Mobil

📻
🔘 FM
⚪ AM

Tekan satu tombol → tombol lain otomatis lepas.

Penjelasan Analogi

Nama "Radio" berasal dari tombol stasiun radio mobil jadul: saat kamu menekan satu tombol, tombol lain otomatis terlepas. Hanya satu yang aktif.

💻 Kode Radio

Radio<String>
String? gender; Radio<String>( value: 'L', groupValue: gender, onChanged: (val) => setState(() => gender = val), ), Radio<String>( value: 'P', groupValue: gender, onChanged: (val) => setState(() => gender = val), ),

🎬 Demo Interaktif

Jenis Kelamin
Topik 7 • Point Materi

Date Picker

showDatePicker memunculkan kalender agar user memilih tanggal — misalnya tanggal lahir.

📅 Analogi: Kalender Dinding

📆
🖐️ memilih tanggal…

Tunjuk satu tanggal di kalender.

Penjelasan Analogi

Seperti menunjuk satu kotak di kalender dinding. Daripada mengetik "12/08/2009" yang rawan salah, user cukup menunjuk tanggalnya.

💻 Kode Date Picker

showDatePicker (async / await)
DateTime? tanggal; Future<void> pilihTanggal() async { final hasil = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(2000), lastDate: DateTime(2030), ); if (hasil != null) { setState(() => tanggal = hasil); } }

🎬 Demo Interaktif

Tanggal Lahir
Topik 8 • Point Materi

Time Picker

showTimePicker memunculkan jam agar user memilih waktu — misalnya jam janji temu.

⏰ Analogi: Mengatur Alarm

🕐 putar jarum jam…

Atur jam & menit lalu OK.

Penjelasan Analogi

Persis seperti menyetel alarm di HP: kamu memutar jam & menit lalu menekan OK. Time Picker mengembalikan objek TimeOfDay.

💻 Kode Time Picker

showTimePicker
TimeOfDay? waktu; Future<void> pilihWaktu() async { final hasil = await showTimePicker( context: context, initialTime: TimeOfDay.now(), ); if (hasil != null) { setState(() => waktu = hasil); } } // Menampilkan: waktu!.format(context)

🎬 Demo Interaktif

Jam Janji Temu
Topik 9 • Flowchart Full Animasi

Form Validation — Alur Lengkap

Saat tombol Submit ditekan, Flutter menjalankan SEMUA validator sekaligus. Inilah alurnya.

Tekan tombol Submit _formKey.currentState .validate() Semua valid? Ya Proses data & simpan tampilkan SnackBar ✓ Tidak Tampilkan pesan error di tiap field & ulangi
Inti Mekanisme

Satu GlobalKey<FormState> memegang seluruh form. Memanggil .validate() akan menjalankan validator setiap field. Jika ada SATU saja yang gagal, hasilnya false dan pesan error muncul serentak.

Topik 9 • Kode Inti

GlobalKey & FormState

Tiga bahan utama: GlobalKey, widget Form, dan pemanggilan .validate().

struktur Form lengkap
final _formKey = GlobalKey<FormState>(); Form( key: _formKey, child: Column( children: [ TextFormField( validator: (v) => v!.isEmpty ? 'Wajib diisi' : null, ), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { // semua field valid → lanjut ScaffoldMessenger.of(context) .showSnackBar(SnackBar( content: Text('Berhasil!'), )); } }, child: Text('Submit'), ), ], ), )

🧩 Penjelasan Tiap Bagian

1. GlobalKey<FormState>

"KTP" unik untuk form, agar kode bisa mengakses & mengontrolnya.

2. Form(key: _formKey)

Pembungkus semua field. Memberi mereka kemampuan validasi bersama.

3. .validate()

Tombol "periksa semua". Mengembalikan true bila seluruh field lolos.

4. .save() (opsional)

Menyimpan nilai tiap field lewat onSaved.

Sintesis

Menggabungkan Semua dalam 1 Form

Sekarang kita rangkai TextFormField, Dropdown, Checkbox, dan Radio menjadi satu form hidup.

form gabungan
Form( key: _formKey, child: Column(children: [ TextFormField( decoration: InputDecoration(labelText: 'Nama'), validator: (v) => v!.isEmpty ? 'Isi nama' : null, ), DropdownButtonFormField<String>( decoration: InputDecoration(labelText: 'Jenjang'), items: ['SMA','SMK','MA'].map((e) => DropdownMenuItem(value: e, child: Text(e)) ).toList(), validator: (v) => v == null ? 'Pilih jenjang' : null, onChanged: (v) {}, ), CheckboxListTile( title: Text('Setuju S&K'), value: setuju, onChanged: (v) => setState(() => setuju = v!), ), ]), )

🎬 Demo Form Mini Hidup

Form Gabungan
Nama wajib diisi
✓ Form valid & terkirim!

Coba tekan Submit dengan field kosong → muncul error. Isi semua → SnackBar hijau.

Mini Project • Overview

Form Pendaftaran Siswa

Proyek puncak BAB 7: satu form pendaftaran lengkap yang memakai semua widget yang kita pelajari.

Field yang Dibutuhkan
  • Nama Lengkap — TextFormField
  • Email — TextFormField + validator @
  • Jenjang — Dropdown
  • Jenis Kelamin — Radio
  • Tanggal Lahir — Date Picker
  • Persetujuan S&K — Checkbox
  • Tombol Daftar — validate() + SnackBar

🎯 Hasil Akhir

Pendaftaran Siswa
Strategi

Kita bangun bertahap: Slide 17 = struktur form & field, Slide 18 = validasi + tombol submit.

Mini Project • Kode Bagian 1

Struktur Form

Kita siapkan StatefulWidget, variabel state, dan kerangka Form-nya.

form_pendaftaran.dart — bagian 1/2
class FormPendaftaran extends StatefulWidget { @override State<FormPendaftaran> createState() => _FormPendaftaranState(); } class _FormPendaftaranState extends State<FormPendaftaran> { final _formKey = GlobalKey<FormState>(); final namaCtrl = TextEditingController(); final emailCtrl = TextEditingController(); String? jenjang; // untuk Dropdown String? gender; // untuk Radio DateTime? tglLahir; // untuk Date Picker bool setuju = false; // untuk Checkbox @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Pendaftaran Siswa')), body: Form( key: _formKey, child: ListView( padding: EdgeInsets.all(16), children: [ TextFormField( controller: namaCtrl, decoration: InputDecoration(labelText: 'Nama Lengkap'), validator: (v) => v!.isEmpty ? 'Nama wajib diisi' : null, ), TextFormField( controller: emailCtrl, decoration: InputDecoration(labelText: 'Email'), validator: (v) => !v!.contains('@') ? 'Email tidak valid' : null, ), DropdownButtonFormField<String>( decoration: InputDecoration(labelText: 'Jenjang'), value: jenjang, items: ['SMA','SMK','MA'].map((e) => DropdownMenuItem(value: e, child: Text(e))).toList(), validator: (v) => v == null ? 'Pilih jenjang' : null, onChanged: (v) => setState(() => jenjang = v), ), // ... lanjut ke Bagian 2 ], ), ), ); } }
Mini Project • Kode Bagian 2

Validasi + Submit

Radio, Checkbox, dan tombol Daftar yang menjalankan validasi seluruh form.

form_pendaftaran.dart — bagian 2/2
// (lanjutan children ListView) // --- Radio Jenis Kelamin --- Row(children: [ Radio<String>(value: 'L', groupValue: gender, onChanged: (v) => setState(() => gender = v)), Text('Laki-laki'), Radio<String>(value: 'P', groupValue: gender, onChanged: (v) => setState(() => gender = v)), Text('Perempuan'), ]), // --- Checkbox Persetujuan --- CheckboxListTile( title: Text('Saya setuju syarat & ketentuan'), value: setuju, onChanged: (v) => setState(() => setuju = v!), ), // --- Tombol Daftar --- ElevatedButton( onPressed: () { if (_formKey.currentState!.validate() && setuju) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text( 'Selamat datang, ${namaCtrl.text}!')), ); } else if (!setuju) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Centang persetujuan dulu')), ); } }, child: Text('Daftar Sekarang'), ),
Selesai!

Form pendaftaran lengkap dengan validasi penuh. Inilah pondasi semua aplikasi nyata: login, registrasi, checkout, dan survei.

Rangkuman • Infografis

Rangkuman BAB 7

⌨️
TextField
Input teks bebas
📝
TextFormField
Teks + validasi
🛡️
Validator
null = valid
📜
Dropdown
Pilih satu (list)
☑️
Checkbox
Ya/tidak, banyak
🔘
Radio
Satu dari grup
📅
Date Picker
Pilih tanggal
Time Picker
Pilih waktu
🔑
GlobalKey
Kendali form
.validate()
Periksa semua
Kunci yang Harus Diingat
  • Validator return null = valid
  • Form butuh GlobalKey<FormState>
  • .validate() jalankan semua validator
  • Date/Time Picker pakai async/await
Dari Sini ke Mana?

BAB selanjutnya: State Management & Navigasi antar halaman — mengirim data form ke layar lain. Form yang kamu kuasai sekarang adalah fondasinya.

Latihan 1 • Tugas Individu

Tugas Individu

⭐ Level Dasar

Form Login Sederhana

Buatlah sebuah halaman Login Flutter yang berisi:

  • Satu TextFormField untuk Email (validator: harus mengandung @)
  • Satu TextFormField untuk Password (validator: minimal 6 karakter, mode obscureText)
  • Satu tombol Login yang memanggil .validate()
  • Tampilkan SnackBar "Login berhasil" bila valid
Kriteria Penilaian
Validator benar (40%) GlobalKey dipakai (25%) obscureText aktif (15%) SnackBar muncul (20%)

Kumpulkan: screenshot tampilan + file .dart. Kerjakan sendiri-sendiri.

Latihan 2 • Tugas Kelompok

Tugas Kelompok

⭐⭐ Level Menengah

Form Pemesanan Makanan

Bersama kelompok (3–4 orang), bangun Form Pemesanan Makanan dengan:

  • TextFormField — Nama pemesan (wajib diisi)
  • Dropdown — Pilih menu (min. 4 pilihan)
  • Radio — Ukuran porsi (Kecil / Sedang / Besar)
  • Checkbox — Topping tambahan (boleh lebih dari satu)
  • Time Picker — Jam pengantaran
  • Tombol Pesan + validasi + SnackBar ringkasan pesanan
Pembagian Peran (saran)
UI LayoutValidator Dropdown & RadioPicker & Submit

Presentasikan hasil di depan kelas. Setiap anggota menjelaskan bagiannya.

Latihan 3 • Challenge Proyek

Challenge Proyek

⭐⭐⭐ Level Mahir

Form Survei Multi-Langkah

Tantangan akhir: buat Form Survei Kepuasan Siswa bertema bebas, dengan minimal:

  • Minimal 2 TextFormField dengan validator berbeda
  • Minimal 1 Dropdown, 1 Radio group, 1 Checkbox group
  • Date Picker dan Time Picker keduanya dipakai
  • Satu GlobalKey<FormState> mengelola seluruh validasi
  • Setelah submit valid, tampilkan ringkasan jawaban di bawah form
  • BONUS: reset form dengan _formKey.currentState!.reset()
Output

Aplikasi berjalan + video demo singkat (1–2 menit) + kode sumber rapi.

Nilai Plus

Desain UI menarik, pesan error yang ramah, dan penggunaan TextEditingController yang benar.

🎓 Selamat! Kamu telah menyelesaikan BAB 7 — Form & Input User.