๐Ÿ“ฑ

Laporan Praktikum Aplikasi Mobile โ€“ Flutter

Form Input Interaktif & Validasi Data
Studi Kasus: Aplikasi Expense Tracker (Modul 3)

Praktikum Aplikasi Mobile 3

Disusun Oleh
Ahmad Zahran
NIM: 2411532004
Dosen Pengampu & Instansi
Nurfiah, S.ST. M.Kom
Departemen Informatika ยท Universitas Andalas (2026)

I. Pendahuluan

Pengembangan aplikasi mobile modern menuntut pembuatan antarmuka pengguna (User Interface) yang tidak hanya menarik dan responsif, tetapi juga mampu mengelola masukan data dari pengguna (user input) secara aman dan terstruktur. Framework Flutter, yang dikembangkan oleh Google menggunakan bahasa pemrograman Dart, menyediakan berbagai widget formulir (form widgets) yang sangat efisien untuk menangani proses pengumpulan data.

Praktikum ini berfokus pada materi pembuatan form input interaktif pada aplikasi Expense Tracker. Konsep dan teknologi utama yang diterapkan meliputi penggunaan Form, TextFormField, DropdownButtonFormField, pemanfaatan TextEditingController untuk menangkap nilai input, validasi input formulir menggunakan GlobalKey<FormState>, pemanggilan komponen interaktif berupa showDatePicker untuk memilih tanggal, serta menampilkan umpan balik ke pengguna menggunakan SnackBar.

Hubungan materi ini dengan pemrograman Dart/Flutter terletak pada penerapan komponen StatefulWidget untuk mengelola state atau status dinamis dari elemen-elemen formulir, seperti perubahan pilihan kategori pada dropdown serta pembaruan nilai tanggal pada pengontrol teks. Pemanggilan metode setState() digunakan untuk memicu perenderan ulang antarmuka saat variabel state berubah. Selain itu, manajemen memori juga diperhatikan melalui pelepasan resource pengontrol menggunakan metode dispose().

Materi ini sangat penting bagi mahasiswa Informatika karena formulir merupakan salah satu komponen paling mendasar dalam aplikasi interaktif. Pemahaman mengenai validasi data, pemilihan tipe input keyboard yang tepat, serta penyediaan antarmuka pemilihan tanggal yang user-friendly akan membentuk kebiasaan pemrosesan data yang aman dan meningkatkan pengalaman pengguna (user experience).

II. Tujuan Praktikum

1

Memahami struktur dan implementasi formulir interaktif di Flutter menggunakan widget Form dan TextFormField.

2

Menerapkan TextEditingController untuk mengelola, membaca, dan mereset nilai masukan teks.

3

Menggunakan GlobalKey<FormState> untuk melakukan validasi masukan formulir sebelum data diproses.

4

Menerapkan widget DropdownButtonFormField untuk menyediakan pilihan kategori secara dinamis.

5

Mengintegrasikan fungsi pemilih tanggal (showDatePicker) asynchronous serta memformat string tanggal secara manual tanpa paket tambahan.

6

Menerapkan ScaffoldMessenger dan SnackBar untuk memberikan konfirmasi visual saat data transaksi berhasil disimpan.

7

Menghubungkan halaman formulir (AddTransactionScreen) dengan berkas utama aplikasi (main.dart).

III. Langkah Praktikum

Berikut adalah langkah-langkah implementasi praktikum pembuatan form input interaktif pada aplikasi Expense Tracker yang disusun secara bertahap:

Langkah 1 โ€” Konfigurasi Utama Aplikasi dan Inisialisasi Tema (main.dart)

Nama/Judul Langkah: Konfigurasi Root App dan Halaman Utama

Kode Program (main.dart)
import 'package:flutter/material.dart'; import 'add_transaction_screen.dart'; // Memanggil file form input void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Expense Tracker - Modul 3', theme: ThemeData( primarySwatch: Colors.deepPurple, // Tema warna Modul 3 ), home: const AddTransactionScreen(), // Langsung membuka halaman Form ); } }

Penjelasan Kode:

  • import 'package:flutter/material.dart';: Mengimpor pustaka komponen UI Material Design dari Flutter.
  • import 'add_transaction_screen.dart';: Mengimpor berkas formulir AddTransactionScreen agar dapat dipanggil sebagai halaman utama.
  • void main() => runApp(const MyApp());: Titik masuk (entry point) utama program yang menjalankan widget MyApp.
  • class MyApp extends StatelessWidget: Kelas widget root aplikasi yang bersifat statis (tidak memiliki state internal yang berubah).
  • MaterialApp: Widget pembungkus utama yang mengatur konfigurasi tema, judul aplikasi, dan navigasi awal.
  • debugShowCheckedModeBanner: false: Menghilangkan pita debug di pojok kanan atas layar.
  • primarySwatch: Colors.deepPurple: Menentukan tema warna ungu utama aplikasi.
  • home: const AddTransactionScreen(): Menetapkan halaman formulir tambah transaksi sebagai antarmuka awal saat aplikasi dijalankan.

Hasil Praktikum:

Hasil Langkah 1 - Konfigurasi Utama Aplikasi
Gambar 3.1: Halaman Utama Catat Transaksi Baru
Langkah 2 โ€” Struktur Kelas Stateful dan Deklarasi Pengontrol Formulir (add_transaction_screen.dart)

Nama/Judul Langkah: Deklarasi Widget, State, Controller, dan Variabel State

Kode Program (add_transaction_screen.dart)
import 'package:flutter/material.dart'; class AddTransactionScreen extends StatefulWidget { const AddTransactionScreen({super.key}); @override State<AddTransactionScreen> createState() => _AddTransactionScreenState(); } class _AddTransactionScreenState extends State<AddTransactionScreen> { final _formKey = GlobalKey<FormState>(); final _titleController = TextEditingController(); final _amountController = TextEditingController(); final _dateController = TextEditingController(); // controller baru untuk tanggal String _selectedCategory = 'Makanan'; final List<String> _categories = [ 'Makanan', 'Transportasi', 'Hiburan', 'Lainnya', ]; @override void dispose() { _titleController.dispose(); _amountController.dispose(); _dateController.dispose(); // jangan lupa dispose controller baru super.dispose(); }

Penjelasan Kode:

  • class AddTransactionScreen extends StatefulWidget: Mengimplementasikan widget berbasis state dinamis karena formulir membutuhkan interaksi perubahan masukan data.
  • _formKey = GlobalKey<FormState>(): Kunci global unik untuk mengidentifikasi dan mengontrol status validasi formulir Form.
  • _titleController, _amountController, _dateController: Objek TextEditingController yang digunakan untuk membaca, mengubah, dan mengontrol teks pada masing-masing bidang input judul, nominal, dan tanggal.
  • String _selectedCategory = 'Makanan': Variabel state untuk menyimpan nilai kategori yang sedang dipilih, dengan nilai awal default 'Makanan'.
  • List<String> _categories: Daftar opsi pilihan kategori transaksi.
  • void dispose(): Metode siklus hidup (lifecycle method) yang dipanggil saat widget dihapus dari pohon widget; berfungsi melepaskan memori pengontrol teks agar tidak terjadi kebocoran memori (memory leak).

Hasil Praktikum: Langkah ini merupakan pembuatan logika internal dan pengontrol state aplikasi sehingga tidak menghasilkan perubahan fisik antarmuka secara langsung tanpa komponen UI pendukung.

Langkah 3 โ€” Fungsi Pemilih Tanggal Asynchronous (_pickDate)

Nama/Judul Langkah: Implementasi Date Picker dan Formats Date String

Kode Program (_pickDate)
// Fungsi untuk menampilkan date picker dan mengisi controller tanggal Future<void> _pickDate() async { final DateTime? picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(2000), lastDate: DateTime(2100), ); if (picked != null) { // Format manual ke DD/MM/YYYY tanpa perlu package tambahan final String day = picked.day.toString().padLeft(2, '0'); final String month = picked.month.toString().padLeft(2, '0'); final String year = picked.year.toString(); setState(() { _dateController.text = "$day/$month/$year"; }); } }

Penjelasan Kode:

  • Future<void> _pickDate() async: Fungsi pemroses asynchronous yang mengembalikan objek Future untuk menangani operasi berdurasi (menunggu pilihan pengguna dari dialog kalender).
  • await showDatePicker(...): Fungsi bawaan Flutter untuk menampilkan dialog pemilih tanggal Material dengan rentang tahun dari 2000 hingga 2100 serta nilai awal tanggal hari ini (DateTime.now()).
  • if (picked != null): Memeriksa apakah pengguna memilih tanggal atau membatalkan dialog.
  • padLeft(2, '0'): Memformat string hari dan bulan agar selalu terdiri dari 2 digit angka (misalnya tanggal 5 menjadi "05").
  • setState(...): Memperbarui nilai teks pada _dateController dengan format "DD/MM/YYYY" sekaligus memicu perenderan ulang tampilan UI.

Hasil Praktikum: Memperlihatkan antarmuka modal dialog pemilih tanggal (Date Picker) yang muncul ketika kolom atau tombol tanggal ditekan.

Langkah 4 โ€” Penyusunan Layout Formulir dan Elemen Input Teks

Nama/Judul Langkah: Penyusunan Form, TextFormField Judul, Nominal, dan Dropdown Kategori

Kode Program (Layout & Elemen Form)
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Catat Transaksi Baru"), backgroundColor: Colors.deepPurple, foregroundColor: Colors.white, ), body: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Input 1: Judul Transaksi TextFormField( controller: _titleController, decoration: const InputDecoration( labelText: "Judul Transaksi", border: OutlineInputBorder(), prefixIcon: Icon(Icons.title), ), validator: (value) { if (value == null || value.isEmpty) { return "Judul transaksi tidak boleh kosong"; } return null; }, ), const SizedBox(height: 16), // Input 2: Nominal Saldo (Keyboard Angka) TextFormField( controller: _amountController, keyboardType: TextInputType.number, decoration: const InputDecoration( labelText: "Nominal (Rp)", border: OutlineInputBorder(), prefixIcon: Icon(Icons.attach_money), ), validator: (value) { if (value == null || value.isEmpty) { return "Nominal wajib diisi"; } if (int.tryParse(value) == null) { return "Harus berupa angka bulat yang valid"; } return null; }, ), const SizedBox(height: 16), // Input 3: Kategori Dropdown DropdownButtonFormField<String>( value: _selectedCategory, decoration: const InputDecoration( labelText: "Kategori", border: OutlineInputBorder(), prefixIcon: Icon(Icons.category), ), items: _categories.map((String category) { return DropdownMenuItem<String>( value: category, child: Text(category), ); }).toList(), onChanged: (String? newValue) { setState(() { _selectedCategory = newValue!; }); }, ),

Penjelasan Kode:

  • Scaffold: Menyediakan struktur visual dasar halaman seperti appBar ungu dan body.
  • SingleChildScrollView: Membungkus konten area kerja agar dapat digulirkan dan mencegah kebocoran/masalah tata letak (overflow) saat keyboard virtual muncul.
  • Form(key: _formKey): Container pengelompok elemen formulir yang terikat dengan kunci validasi _formKey.
  • Column(crossAxisAlignment: CrossAxisAlignment.stretch): Menyusun elemen input secara vertikal dan merenggangkan lebar elemen agar memenuhi area layar.
  • TextFormField (Judul): Bidang masukan teks judul transaksi yang dilengkapi ikon Icons.title dan pemeriksaan pesan galat jika nilai kosong.
  • TextFormField (Nominal): Bidang masukan angka dengan keyboardType: TextInputType.number untuk menampilkan keyboard angka, serta validasi memeriksa apakah masukan merupakan angka bulat (int.tryParse).
  • DropdownButtonFormField: Menampilkan pilihan opsi kategori. Fungsi onChanged memanggil setState() untuk mengubah variabel state _selectedCategory saat opsi dipilih.
Langkah 5 โ€” Input Tanggal, Tombol Simpan, Validasi, dan SnackBar

Nama/Judul Langkah: Input Tanggal Read-Only, Validasi Formulir, dan Notifikasi SnackBar

Kode Program (Input Tanggal & Aksi Simpan)
const SizedBox(height: 16), // Input 4: Tanggal Transaksi (BARU) TextFormField( controller: _dateController, readOnly: true, // mencegah user mengetik format bebas decoration: InputDecoration( labelText: "Tanggal Transaksi", hintText: "DD/MM/YYYY", border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.calendar_today), suffixIcon: IconButton( icon: const Icon(Icons.add), onPressed: _pickDate, // tombol plus memanggil showDatePicker ), ), onTap: _pickDate, // bisa juga tap di field-nya langsung validator: (value) { if (value == null || value.isEmpty) { return "Tanggal transaksi wajib diisi"; } return null; }, ), const SizedBox(height: 32), // Tombol Simpan ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.deepPurple, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), ), onPressed: () { if (_formKey.currentState!.validate()) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Tersimpan: ${_titleController.text} ' '(Rp ${_amountController.text}) ' 'pada ${_dateController.text}', ), backgroundColor: Colors.green, ), ); } }, child: const Text( "Simpan Transaksi", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), ], ), ), ), ); } }

Penjelasan Kode:

  • TextFormField (Tanggal): Kolom input tanggal yang diset readOnly: true agar pengguna tidak mengetik manual, melainkan memilih melalui kalender interaktif. Mengklik kolom (onTap) atau ikon plus (suffixIcon) akan menjalankan aksi _pickDate.
  • ElevatedButton: Tombol utama berwarna ungu untuk memproses penyimpanan data.
  • _formKey.currentState!.validate(): Menjalankan fungsi validator pada seluruh bidang TextFormField di dalam Form. Mengembalikan nilai true jika seluruh bidang masukan valid.
  • ScaffoldMessenger.of(context).showSnackBar(...): Menampilkan umpan balik pesan pop-up hijau di bagian bawah layar berisi rincian teks judul, nominal, dan tanggal transaksi yang berhasil disimpan.

Hasil Praktikum:

Hasil Langkah 5 - Form Lengkap dengan Input Tanggal
Gambar 3.2: Formulir Tambah Transaksi Lengkap

IV. Kesimpulan

Hasil & Kesimpulan Praktikum
  • Berdasarkan seluruh Rangkaian kegiatan praktikum yang telah dilakukan, dapat disimpulkan bahwa:
  • Pembuatan formulir interaktif pada Flutter dapat diimplementasikan dengan sangat terstruktur menggunakan kombinasi widget Form, TextFormField, dan DropdownButtonFormField.
  • Penggunaan TextEditingController memudahkan proses pengontrolan dan pengambilan data dari elemen input teks, sedangkan pembatalan memori melalui metode dispose() memastikan aplikasi berjalan efisien.
  • Validasi masukan data berhasil diterapkan menggunakan GlobalKey<FormState>, yang secara otomatis memeriksa kelayakan nilai input sebelum diproses lebih lanjut.
  • Fitur pemilih tanggal interaktif (showDatePicker) dan pemformatan teks manual memberikan fleksibilitas tanpa perlu ketergantungan pada dependensi paket pihak ketiga tambahan.
  • Penggunaan ScaffoldMessenger dan SnackBar memberikan umpan balik langsung yang informatif kepada pengguna saat transaksi berhasil disimpan.
  • Integrasi antara komponen UI, pengelolaan state lokal, dan alur validasi formulir pada kode program berhasil menghasilkan aplikasi pencatat transaksi yang responsif, adaptif, dan bebas dari error layout.
๐Ÿ™
Source Code Repository
Lihat seluruh kode program Aplikasi Mobile di GitHub (Branch Praktikum 3)
AhmadZahran1011 / AppMobile-AhmadZahran (praktikum3)