Mengenal Widget Form


Widget Form adalah salah satu widget yang digunakan untuk membuat form input pada aplikasi Flutter. Form ini memungkinkan pengguna untuk mengisi data dan mengirimkannya ke server atau menyimpannya secara lokal.

View on GitHub

Pendahuluan

1.1 Tujuan
Tujuan praktikum ini yaitu mahasiswa mampu membuat basic form untuk menerima inputan dari keyboard dan mengelola inputan:

1.2 Alat

Teori

Basic Form

Basic Form merupakan widget yang berfungsi sebagai inputan nilai seperti TextField, TextFormField, CheckBox, Switch, Dropdown, Radio, Dialog, DatePicker, BottomSheet, Snackbar dan lain-lain. Basic Form digunakan untuk validasi dan mengelola inputan dari berbagai field.

Form akan memberikan tampilan inputan kemudian inputan akan diperiksa apakah sudah sesuai dengan aturan atau format yang ditetapkan, selanjutnya data inputan akan diambil nilainya setelah proses pengecekan selesai dilakukan.

TextField

TextField adalah widget yang digunakan untuk memasukkan teks oleh pengguna, biasanya digunakan untuk membuat form inputan seperti login, pencarian, dll.

TextField(
  decoration: InputDecoration(
    labelText: 'Nama Lengkap',
    hintText: 'Misalnya masnoer',
    border: OutlineInputBorder(),
    prefixIcon: Icon(Icons.person),
  ),
  controller: _textEditingController,
  keyboardType: TextInputType.text,
  onChanged: (text) {
    print('Sedang mengetik teks: $text');
  },
)
TextFormField

TextFormField adalah versi lengkap dari TextField yang terintegrasi dengan logika validasi dan manajemen state dari sebuah form.

TextFormField(
  controller: _nameController,
  decoration: InputDecoration(
    labelText: "Nama : ",
    border: OutlineInputBorder(),
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Masukkan nama anda';
    }
    return null;
  },
)
GlobalKey & FormState

GlobalKey digunakan untuk mengakses state widget secara global. Dengan FormState, kita bisa memanggil metode seperti validate() atau save() dari luar widget.

validate()

Metode validate() digunakan untuk menjalankan validasi pada setiap TextFormField dalam Form. Jika semua validator mengembalikan null, maka hasilnya true; jika ada error, akan mengembalikan false dan menampilkan pesan error.

setState()

setState() digunakan untuk memberitahu Flutter bahwa ada perubahan state pada StatefulWidget dan perlu dilakukan rebuild.

setState(() {
  // perubahan state
});
const

Kata kunci const digunakan untuk membuat widget menjadi konstanta saat kompilasi. Ini meningkatkan performa karena widget tidak akan di-rebuild jika tidak berubah.

// Non-const
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('My App'),
    ),
    body: Center(
      child: Text('Hello World!'),
    ),
  );
}

// Const
Widget build(BuildContext context) {
  return const Scaffold(
    appBar: AppBar(
      title: Text('My App'),
    ),
    body: Center(
      child: Text('Hello World!'),
    ),
  );
}

Langkah-langkah

Basic Form TextField
  1. Buat file dart baru dengan nama form-textfield.dart di dalam folder lib.
  2. Buat tampilan basic form dengan menggunakan widget TextField untuk inputan, dan ElevatedButton untuk memberikan event listener. Gunakan kode program berikut:
import 'package:flutter/material.dart';

class FormApp extends StatelessWidget {
  const FormApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Basic Form')),
        body: const MyForm(),
      ),
    );
  }
}

class MyForm extends StatefulWidget {
  const MyForm({super.key});

  @override
  State<MyForm> createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text('Masukkan nama anda :'),
          const SizedBox(height: 10),
          const TextField(
            decoration: InputDecoration(
              labelText: 'Nama Lengkap',
              hintText: 'Misalnya masnoer',
              border: OutlineInputBorder(),
              prefixIcon: Icon(Icons.person),
            ),
          ),
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: () {},
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.amber,
              foregroundColor: Colors.black,
            ),
            child: const Text('Tampilkan mama'),
          ),
        ],
      ),
    );
  }
}
Hasil TextField
Card image cap
Contoh Form Pendaftaran
import 'package:flutter/material.dart';

class LoginForm extends StatelessWidget {
  const LoginForm({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text("Basic Form TextFormField")),
        body: const MyFormText(),
      ),
    );
  }
}

class MyFormText extends StatefulWidget {
  const MyFormText({super.key});

  @override
  State<MyFormText> createState() => _MyFormTextState();
}

class _MyFormTextState extends State<MyFormText> {
  final _formKey = GlobalKey<FormState>();
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();

  @override
  void dispose() {
    _nameController.dispose();
    _emailController.dispose();
    super.dispose();
  }

  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      String name = _nameController.text;
      String email = _emailController.text;

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Validasi $name, $email Berhasil')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            const SizedBox(height: 10),
            TextFormField(
              controller: _nameController,
              decoration: const InputDecoration(
                labelText: "Nama : ",
                border: OutlineInputBorder(),
              ),
              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Masukkan nama anda';
                }
                return null;
              },
            ),
            const SizedBox(height: 10),
            TextFormField(
              controller: _emailController,
              decoration: const InputDecoration(
                labelText: "Email : ",
                border: OutlineInputBorder(),
              ),
              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Masukkan email anda ';
                }
                if (!value.contains('@')) {
                  return 'Email tidak valid';
                }
                return null;
              },
            ),
            const SizedBox(height: 10),
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                onPressed: _submitForm,
                child: const Text('Submit'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
Hasil
Card image cap Card image cap

Latihan / Tugas

Kelas B: Implementasi Basic Form Flutter

Buatlah form pendaftaran pengguna dengan menggunakan 4 buah form yaitu nama, email, password, confirm password, dan satu tombol submit.

Instruksi:

Penyelesaian

Kodingan
import 'package:flutter/material.dart';

class RegisterWidget extends StatefulWidget {
  const RegisterWidget({super.key});

  @override
  State<RegisterWidget> createState() => _RegisterWidgetState();
}

class _RegisterWidgetState extends State<RegisterWidget> {
  final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _confirmController = TextEditingController();
  final _usernameController = TextEditingController();

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    _confirmController.dispose();
    _usernameController.dispose();
    super.dispose();
  }

  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      print(
        'Registering: ${_usernameController.text}, ${_emailController.text}',
      );
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Mendaftarkan ${_usernameController.text}...')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.all(40.0),
      child: Form(
        key: _formKey,
        child: Column(
          children: [
            TextFormField(
              decoration: const InputDecoration(
                labelText: 'Nama pengguna',
                prefixIcon: Icon(Icons.person),
              ),
              controller: _usernameController,

              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Tidak boleh kosong!';
                }
                return null;
              },
            ),
            const SizedBox(height: 16),
            TextFormField(
              decoration: const InputDecoration(
                labelText: 'Email',
                prefixIcon: Icon(Icons.email),
              ),
              controller: _emailController,

              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Email wajib diisi';
                } else if (!emailRegex.hasMatch(value)) {
                  return 'Format email tidak valid';
                }
                return null;
              },
            ),
            const SizedBox(height: 16),
            TextFormField(
              decoration: const InputDecoration(
                labelText: 'Kata sandi',
                prefixIcon: Icon(Icons.lock),
              ),
              controller: _passwordController,
              obscureText: true,

              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Kata sandi wajib diisi';
                }
                if (value.length < 6) {
                  return 'Kata sandi tidak boleh kecil dari 6';
                }
                return null;
              },
            ),
            const SizedBox(height: 16),
            TextFormField(
              decoration: const InputDecoration(
                labelText: 'Konfirmasi kata sandi',

                prefixIcon: Icon(Icons.lock),
              ),
              obscureText: true,
              controller: _confirmController,

              validator: (value) => value == _passwordController.text
                  ? null
                  : 'Kata sandi tidak cocok',
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: _submitForm,
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.deepPurple,
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(
                  horizontal: 32,
                  vertical: 14,
                ),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12),
                ),
                elevation: 6,
                textStyle: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                  letterSpacing: 1.2,
                ),
              ),
              child: const Text('Daftar Sekarang'),
            ),
          ],
        ),
      ),
    );
  }
}
Hasil
Card image cap Card image cap
Tombol ke Repository Proyes:


Document