Belajar Flutter - Input, Forms, & Interaction
Episode 5 of 23

Belajar Flutter - Input, Forms, & Interaction

Episode ini membuat aplikasi Flutter kalian benar-benar interaktif: handling user input dengan TextField, buttons, dan gestures, form validation dengan controllers, navigation dan routing sederhana, serta penggunaan SnackBar, dialogs, dan modal bottom sheets.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

Sejauh ini kalian hanya menampilkan teks statis. Episode 5 mengubah itu: kalian akan belajar menangkap input dari pengguna dan meresponsnya. Inilah titik di mana aplikasi mulai terasa hidup. Kita akan membahas empat area interaksi: TextField, buttons, dan gestures untuk menangkap input; Form dengan validation dan controllers; navigation dan routing sederhana antar halaman; serta SnackBar, dialogs, dan modal bottom sheets untuk umpan balik dan konfirmasi.

Handling User Input

TextField dan Buttons

TextField adalah pintu input teks, dan ElevatedButton adalah tombol utama Material:

TextField dengan tombol aksi
final TextEditingController _controller = TextEditingController();
 
TextField(
  controller: _controller,
  decoration: const InputDecoration(
    labelText: 'Nama',
    border: OutlineInputBorder(),
  ),
),
 
ElevatedButton(
  onPressed: () {
    print(_controller.text);
  },
  child: const Text('Kirim'),
)

_controller.text membaca nilai yang diketik pengguna. Setiap TextEditingController yang dibuat manual harus dibuang di dispose untuk mencegah memory leak.

GestureDetector dan InkWell

Untuk interaksi bebas selain tombol, gunakan GestureDetector atau InkWell — yang terakhir memberi efek riak Material:

Menangkap gesture tap
InkWell(
  onTap: () {
    print('Ditekan');
  },
  child: const Padding(
    padding: EdgeInsets.all(8),
    child: Text('Ketik di sini'),
  ),
)

InkWell mendukung banyak gesture: onTap, onDoubleTap, dan onLongPress. Gunakan GestureDetector hanya saat tidak butuh efek Material. Opsi callback lain yang sering dipakai adalah onDoubleTap untuk aksi sekunder.

Form Validation dan Controllers

Form dengan Validator

Gabungkan Form, TextFormField, dan validator untuk validasi terpusat:

Form dengan validasi email
final _formKey = GlobalKey<FormState>();
 
Form(
  key: _formKey,
  child: Column(
    children: [
      TextFormField(
        decoration: const InputDecoration(labelText: 'Email'),
        validator: (value) {
          if (value == null || !value.contains('@')) {
            return 'Masukkan email yang valid';
          }
          return null;
        },
      ),
      ElevatedButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {
            print('Form valid');
          }
        },
        child: const Text('Simpan'),
      ),
    ],
  ),
)

_formKey.currentState!.validate() menjalankan semua validator dan mengembalikan true jika semuanya lolos. Error validator ditampilkan otomatis di bawah field.

Pindah Halaman dengan Navigator

Navigasi paling sederhana memakai Navigator.push dengan MaterialPageRoute:

Navigasi ke halaman baru
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const HalamanDetail(),
  ),
);

Navigator.push menumpuk halaman baru di atas halaman saat ini, lengkap dengan animasi default. Kembali ke halaman sebelumnya cukup dengan Navigator.pop(context).

Mengirim dan Menerima Hasil

Menerima hasil dari halaman baru
final hasil = await Navigator.push<String>(
  context,
  MaterialPageRoute(builder: (context) => const HalamanPilih()),
);
 
if (hasil != null) {
  print('Dipilih: $hasil');
}

Pola await Navigator.push dan Navigator.pop(context, hasil) adalah cara standar mengirim data hasil — dasar dari alur wizard yang akan kita bahas di episode 11.

SnackBar, Dialogs, dan Modal Bottom Sheets

SnackBar untuk Umpan Balik Singkat

Tampilkan notifikasi singkat dengan ScaffoldMessenger:

Menampilkan SnackBar
ScaffoldMessenger.of(context).showSnackBar(
  const SnackBar(
    content: Text('Perubahan tersimpan'),
    duration: Duration(seconds: 2),
  ),
);

SnackBar muncul di bagian bawah layar dan menghilang otomatis. Tempatkan di dalam ScaffoldMessenger.of(context).showSnackBar agar terikat dengan benar pada Scaffold.

Dialog dan Modal Bottom Sheet

Untuk konfirmasi, gunakan dialog; untuk menu kontekstual, gunakan bottom sheet:

Dialog konfirmasi sederhana
showDialog<void>(
  context: context,
  builder: (context) => AlertDialog(
    title: const Text('Hapus data?'),
    content: const Text('Tindakan ini tidak bisa dibatalkan.'),
    actions: [
      TextButton(
        onPressed: () => Navigator.pop(context, false),
        child: const Text('Batal'),
      ),
      TextButton(
        onPressed: () => Navigator.pop(context, true),
        child: const Text('Hapus'),
      ),
    ],
  ),
);

showDialog menampilkan dialog modal; tombol di actions menutup dialog dengan mengembalikan nilai. Pola yang sama dipakai showModalBottomSheet untuk panel yang meluncur dari bawah.

Penutup

Inti yang harus dibawa pulang:

  • TextField dengan TextEditingController menangkap input; buang controller di dispose.
  • InkWell memberi gesture dengan efek Material; GestureDetector tanpa efek.
  • Form dengan validator memberikan validasi terpusat yang konsisten.
  • Navigator.push menumpuk halaman; Navigator.pop(context, hasil) mengembalikan hasil.
  • SnackBar untuk umpan balik singkat; dialog dan bottom sheet untuk keputusan.
  • Selalu validasi input sebelum mengirim data ke backend.

Di episode 6 selanjutnya kita membahas state management dasar — mengelola state lokal dengan setState(), teknik lifting state up dan prop drilling, pengenalan pattern Provider dan InheritedWidget, serta best practice untuk state skala kecil. Ini jembatan dari widget individual ke aplikasi yang utuh.