Report 3 AppMobile — Input Widgets & Forms

Aplikasi Mobile Semester 5 Putri Balqis Afradinata

I. Tujuan Praktikum

  • Menangkap teks dari pengguna menggunakan controller.
  • Menerapkan widget dropdown statis.
  • Menerapkan validasi input untuk mencegah data kosong atau format yang salah.

II. Dasar Teori

Praktikum III membahas Input Widgets & Forms pada Flutter, yaitu cara menangkap data dari pengguna melalui form, menggunakan controller, dropdown, serta validasi input sebelum data diproses.

TextFormField digunakan untuk menerima data dari pengguna sekaligus mendukung proses validasi melalui property validator. Validator memeriksa isi kolom dan mengembalikan null apabila data valid atau String berisi pesan error apabila data tidak valid.

GlobalKey<FormState> digunakan untuk mengontrol Form dan menjalankan proses validasi menggunakan method validate(). Dengan demikian, seluruh input dapat diperiksa ketika pengguna menekan tombol Simpan.

TextEditingController digunakan untuk mengambil teks yang dimasukkan pengguna pada field judul dan nominal. Controller perlu dibersihkan menggunakan method dispose() ketika halaman tidak lagi digunakan.

DropdownButtonFormField digunakan untuk memberikan pilihan kategori yang telah ditentukan. Pada praktikum ini kategori yang digunakan adalah Makanan, Transportasi, Hiburan, dan Lainnya.

III. Langkah-Langkah Praktikum

  1. Membuat File add_transaction_screen.dart
    Langkah pertama yaitu membuat file Dart baru di dalam folder lib dengan nama add_transaction_screen.dart. File ini digunakan untuk membuat halaman formulir input transaksi.
    lib/add_transaction_screen.dart
    Membuat add_transaction_screen.dart
  2. Menyiapkan StatefulWidget
    Form menggunakan StatefulWidget karena isi formulir, seperti teks input dan pilihan dropdown, dapat berubah ketika pengguna berinteraksi dengan aplikasi.
    class AddTransactionScreen extends StatefulWidget {
      const AddTransactionScreen({super.key});
    
      @override
      State<AddTransactionScreen> createState() =>
          _AddTransactionScreenState();
    }

    Penggunaan StatefulWidget memungkinkan aplikasi memperbarui nilai state dropdown dan data input selama form digunakan.

  3. Menyiapkan GlobalKey dan Controller
    Selanjutnya dibuat GlobalKey untuk mengontrol form dan TextEditingController untuk mengambil nilai dari input judul dan nominal.
    final _formKey = GlobalKey<FormState>();
    
    final _titleController = TextEditingController();
    final _amountController = TextEditingController();

    GlobalKey digunakan untuk memicu validasi, sedangkan controller digunakan untuk mengambil teks yang dimasukkan pengguna.

  4. Menyiapkan State Dropdown
    Dropdown dibuat menggunakan sebuah variabel untuk menyimpan kategori yang sedang dipilih dan list kategori yang tersedia.
    String _selectedCategory = 'Makanan';
    
    final List<String> _categories = [
      'Makanan',
      'Transportasi',
      'Hiburan',
      'Lainnya'
    ];

    Nilai awal kategori adalah Makanan. Daftar kategori kemudian digunakan sebagai item pada DropdownButtonFormField.

  5. Membuat Fungsi dispose()
    Controller dibersihkan ketika halaman ditutup untuk mencegah penggunaan memori yang tidak diperlukan.
    @override
    void dispose() {
      _titleController.dispose();
      _amountController.dispose();
      super.dispose();
    }

    Method dispose memastikan controller yang digunakan oleh form dilepas ketika widget sudah tidak digunakan.

  6. Membuat Tampilan Form
    Tampilan utama dibuat menggunakan Scaffold, AppBar, SingleChildScrollView, Form, dan Column. Form dihubungkan dengan _formKey.
    body: SingleChildScrollView(
      padding: const EdgeInsets.all(16.0),
      child: Form(
        key: _formKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            ...
          ],
        ),
      ),
    )

    SingleChildScrollView digunakan agar tampilan tetap dapat digulir ketika keyboard muncul pada perangkat.

    Tampilan form transaksi
  7. Membuat Input Judul Transaksi
    Input pertama menggunakan TextFormField yang dihubungkan dengan _titleController. Field diberikan validator untuk memastikan judul tidak kosong.
    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;
      },
    )

    Jika pengguna tidak mengisi judul, validator akan menampilkan pesan error. Jika input valid, validator mengembalikan nilai null.

    Validasi judul transaksi
  8. Membuat Input Nominal
    Input nominal menggunakan TextFormField dengan keyboardType: TextInputType.number agar perangkat menampilkan 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;
      },
    )

    Validator nominal memeriksa dua kondisi, yaitu nominal tidak boleh kosong dan nilai yang dimasukkan harus berupa angka bulat yang valid.

    Validasi nominal
    Validasi nominal
  9. Membuat Dropdown Kategori
    Dropdown dibuat menggunakan DropdownButtonFormField<String>. Item dropdown diambil dari list kategori yang telah dibuat sebelumnya.
    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!;
        });
      },
    )

    Ketika pengguna memilih kategori baru, nilai _selectedCategory diperbarui menggunakan setState().

    Hasil dropdown kategori
  10. Membuat Tombol Simpan dan Validasi
    Tombol Simpan digunakan untuk menjalankan validasi keseluruhan form. Validasi dilakukan menggunakan _formKey.currentState!.validate().
    onPressed: () {
      if (_formKey.currentState!.validate()) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text(
              'Tersimpan: ${_titleController.text} '
              '(Rp ${_amountController.text})',
            ),
            backgroundColor: Colors.green,
          ),
        );
      }
    }

    Jika seluruh input memenuhi aturan validasi, aplikasi menampilkan SnackBar berisi informasi transaksi yang berhasil disimpan.

    SnackBar sukses
  11. Membuat main.dart
    File main.dart digunakan untuk menjalankan aplikasi dan membuka halaman AddTransactionScreen.
    lib/main.dart
    
    import 'package:flutter/material.dart';
    import 'add_transaction_screen.dart';
    
    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,
          ),
          home: const AddTransactionScreen(),
        );
      }
    }

    Setelah main.dart dijalankan, aplikasi langsung membuka halaman formulir transaksi.

IV. Tugas Praktikum

Pada tugas praktikum Modul 3, ditambahkan satu input baru sebelum tombol Simpan untuk mengisi Tanggal Transaksi. Modul menyediakan dua alternatif, yaitu menggunakan TextFormField biasa dengan format teks DD/MM/YYYY atau menggunakan tombol tambahan yang memanggil fungsi showDatePicker. Input tanggal wajib diberikan validasi agar tidak boleh kosong. fileciteturn0file0L195-L201

  1. Menambahkan Input Tanggal Transaksi
    Pada form ditambahkan field tanggal sebelum tombol Simpan. Salah satu implementasi yang dapat digunakan adalah TextFormField dengan controller khusus tanggal.
    final _dateController = TextEditingController();
    
    TextFormField(
      controller: _dateController,
      decoration: const InputDecoration(
        labelText: "Tanggal Transaksi",
        hintText: "DD/MM/YYYY",
        border: OutlineInputBorder(),
        prefixIcon: Icon(Icons.calendar_today),
      ),
      validator: (value) {
        if (value == null || value.isEmpty) {
          return "Tanggal transaksi wajib diisi";
        }
        return null;
      },
    )

    Field tanggal wajib diisi. Jika field kosong ketika tombol Simpan ditekan, validator akan menampilkan pesan error.

    Input tanggal transaksi
    Input tanggal transaksi
  2. Menambahkan Tombol Kalender dengan showDatePicker
    Alternatif yang lebih interaktif adalah menggunakan showDatePicker untuk memilih tanggal melalui kalender.
    Future<void> _pickDate() async {
      final DateTime? picked = await showDatePicker(
        context: context,
        initialDate: DateTime.now(),
        firstDate: DateTime(2000),
        lastDate: DateTime(2100),
      );
    
      if (picked != null) {
        setState(() {
          _dateController.text =
              "${picked.day.toString().padLeft(2, '0')}/"
              "${picked.month.toString().padLeft(2, '0')}/"
              "${picked.year}";
        });
      }
    }

    Ketika pengguna memilih tanggal pada kalender, tanggal tersebut dimasukkan ke dalam field dengan format DD/MM/YYYY.

    ShowDatePicker
  3. Memastikan Validasi Tanggal Berjalan
    Setelah input tanggal ditambahkan, tombol Simpan tetap menggunakan proses validasi Form sehingga tanggal yang kosong tidak dapat dianggap sebagai input yang valid.
    onPressed: () {
      if (_formKey.currentState!.validate()) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text("Data transaksi berhasil divalidasi"),
          ),
        );
      }
    }

    Dengan demikian, seluruh field utama pada form, termasuk tanggal transaksi, diperiksa sebelum data diproses.

    Validasi tanggal
    Validasi tanggal
  4. Hasil Tugas Praktikum
    Setelah tugas selesai, form transaksi memiliki input judul, nominal, kategori, dan tanggal transaksi. Data dapat divalidasi melalui tombol Simpan.
    Hasil tugas Modul 3

V. Hasil dan Pembahasan

Berdasarkan praktikum yang telah dilakukan, aplikasi berhasil menerapkan input widget menggunakan TextFormField untuk menerima judul transaksi dan nominal. Setiap input dihubungkan dengan TextEditingController sehingga nilai yang dimasukkan pengguna dapat diambil ketika proses penyimpanan dilakukan.

Penggunaan keyboardType: TextInputType.number pada nominal membuat field tersebut digunakan khusus untuk input angka. Validator juga memastikan nominal tidak kosong dan harus berupa angka bulat yang valid.

Dropdown berhasil digunakan untuk memilih kategori transaksi. Nilai kategori disimpan pada state _selectedCategory dan diperbarui menggunakan setState() ketika pengguna memilih pilihan yang berbeda.

Proses validasi dilakukan menggunakan Form dan GlobalKey<FormState>. Ketika tombol Simpan ditekan, method validate() memeriksa seluruh field. Jika input memenuhi ketentuan, aplikasi menampilkan SnackBar sebagai informasi bahwa data telah berhasil diproses.

Pada tugas praktikum, input tanggal transaksi ditambahkan sebelum tombol Simpan. Tanggal dapat dimasukkan menggunakan TextFormField dengan format DD/MM/YYYY atau dipilih melalui fungsi showDatePicker. Field tanggal juga diberikan validasi wajib diisi sesuai ketentuan tugas pada modul.

VI. Kesimpulan

Dari praktikum yang telah dilakukan dapat disimpulkan bahwa Flutter menyediakan berbagai input widget yang dapat digunakan untuk menangkap data dari pengguna melalui sebuah form. TextFormField dapat digunakan untuk menerima input sekaligus melakukan validasi menggunakan property validator.

TextEditingController digunakan untuk mengambil nilai input, sedangkan DropdownButtonFormField digunakan untuk memberikan pilihan kategori kepada pengguna. Penggunaan Form dan GlobalKey<FormState> memungkinkan seluruh input divalidasi sebelum data diproses.

Pada tugas praktikum, form dikembangkan dengan menambahkan input tanggal transaksi yang wajib diisi. Dengan penerapan validasi, aplikasi dapat mencegah data kosong atau input yang tidak sesuai sebelum diproses.