Praktikum Aplikasi Mobile 3 – Input Widgets dan Basic Form

Basic Form TextField

Buat sebuah file Dart baru bernama form_textfield.dart di dalam folder lib. Buatlah antarmuka form sederhana menggunakan Widget TextField untuk memasukkan data, serta ElevatedButton untuk menambahkan aksi ketika tombol ditekan. Gunakan kode program berikut sebagai referensi untuk membuat tampilan form.


import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({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 createState() => _MyFormState();
}

class _MyFormState extends State {
  // Tambahkan controller untuk TextField
  TextEditingController _textEditingController = TextEditingController();

  @override
  void dispose() {
    // Bersihkan controller saat widget dihapus dari tree
    _textEditingController.dispose();
    super.dispose();
  }

  @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,
          ),
          TextField(
            decoration: const InputDecoration(
              labelText: 'Nama Lengkap',
              hintText: 'Misalnya renjibuoy',
              border: OutlineInputBorder(),
              prefixIcon: Icon(Icons.person),
            ),
            controller: _textEditingController,
            keyboardType: TextInputType.text,
            onChanged: (text) {
              print('Sedang mengetik teks : ,$text');
            },
          ),
          const SizedBox(
            height: 20,
          ),
          ElevatedButton(
            onPressed: () {
              String inputText = _textEditingController.text;
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Nama anda adalah , $inputText')),
              );
            },
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.amber,
              foregroundColor: Colors.black,
            ),
            child: const Text('Tampilkan nama'),
          ),
        ],
      ),
    );
  }
}

                

run kodenya maka akan outputnya seperti di bawah ini

Di bagian kode class _MyFormState tambahkan kode ini


TextEditingController _textEditingController = TextEditingController();
@override
void dispose() {
_textEditingController.dispose();
super.dispose();
}
                  

outputnya seperti dibawah

TextEditingController digunakan untuk mengontrol dan mengambil nilai dari TextField. dispose() dipanggil saat widget dihapus untuk membersihkan memori dari controller agar tidak terjadi memory leak.

Tambahkan kode ini di bagian Widget TextField


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

TextField dengan controller untuk input nama, ada label, hint, icon, dan mencetak teks setiap kali diketik.

berikut outputnya

Tambahkan kode program berikut pada widget ElevatedButton


           onPressed: () {
  String inputText = _textEditingController.text;
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text('Nama anda adalah: $inputText'),
    ),
  );
},

Kode ini membuat tombol menampilkan teks yang diketik pengguna di TextField melalui SnackBar saat ditekan, sehingga pengguna mendapatkan umpan balik langsung.

Basic Form TextFormField

Buatlah sebuah file baru di dalam folder lib dengan nama form_textformfield.dart. Di dalam file tersebut, buatlah sebuah form sederhana yang terdiri dari dua buah TextFormField untuk memasukkan data dan satu buah ElevatedButton yang akan menjalankan aksi ketika ditekan. Kode program berikut dapat digunakan sebagai panduan untuk membuat tampilan form ini.


import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({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 createState() => _MyFormTextState();
}

class _MyFormTextState extends State {
  final _formKey = GlobalKey();
  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'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Kode ini membuat sebuah form sederhana yang terdiri dari dua TextFormField untuk memasukkan nama dan email, serta sebuah tombol ElevatedButton untuk mengirimkan data. Setiap input dikontrol menggunakan TextEditingController, dan terdapat validasi untuk memastikan nama tidak kosong serta email berisi karakter @. Saat tombol submit ditekan dan semua validasi terpenuhi, sebuah SnackBar akan muncul menampilkan data yang dimasukkan pengguna. Selain itu, metode dispose() digunakan untuk membersihkan controller ketika widget dihapus, mencegah terjadinya memory leak.

berikut outputnya

Pada bagian class _MyFormTextState,masukkan kode berikut :


   final _formKey = GlobalKey();
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')),
    );
  }
}

Kode ini mendefinisikan form dengan kunci global (_formKey) dan controller untuk mengambil input nama dan email. Metode dispose() membersihkan controller saat widget dihapus, sedangkan _submitForm() memeriksa validasi form dan menampilkan SnackBar berisi data yang dimasukkan jika validasi berhasil.

outputnya seperti di bawah

Pada bagian TextFormField, ubah dengan kode berikut.


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

Form input untuk nama dengan validator yang memastikan tidak kosong dan menggunakan TextEditingController untuk mengambil nilai input.

outputnya

bentuk yang lebih lebih lengkap


                 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;
  },
),

Form input untuk email dengan validator yang memastikan tidak kosong dan memiliki karakter @, menggunakan TextEditingController untuk mengambil nilai input.

output seperti ini

Selanjutnya, panggil metode _submitForm di properti onPressed pada ElevatedButton, sesuai contoh kode berikut.


SizedBox(
  width: double.infinity,
  child: ElevatedButton(
    onPressed: _submitForm,
    child: const Text('Submit'),
  ),
),

Tombol Submit yang menempati lebar penuh dan menjalankan _submitForm() saat ditekan.

kode lengkapnya


import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({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 createState() => _MyFormTextState();
}

class _MyFormTextState extends State {
  final _formKey = GlobalKey();
  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'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

penjelasan, Kode ini membuat sebuah form sederhana di Flutter dengan dua input, yaitu nama dan email, serta sebuah tombol Submit. Setiap input dikontrol menggunakan TextEditingController dan divalidasi: nama tidak boleh kosong, email harus mengandung karakter @. Saat tombol Submit ditekan dan semua validasi lolos, sebuah SnackBar muncul menampilkan data yang dimasukkan pengguna. Metode dispose() digunakan untuk membersihkan controller agar tidak terjadi memory leak, sehingga form ini aman dan interaktif.

hasilnya seperti ini

LATIHAN

Implementasi Basic Form Flutter
Buatlah form pendaftaran pengguna dengan menggunakan 4 buah form, yaitu: nama, email, password, confirm password, serta satu tombol submit.

Instruksi:

file 1: main.dart


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

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Form Registration',
      home: const UserRegistrationForm(),
    );
  }
}
                  

Kode ini adalah entry point dari aplikasi Flutter yang menampilkan form registrasi. Fungsi main() memanggil runApp() untuk menjalankan widget MyApp. MyApp adalah StatelessWidget yang membungkus seluruh aplikasi dengan MaterialApp, memberikan tema dan struktur dasar aplikasi. Properti home dari MaterialApp diisi dengan widget UserRegistrationForm, yang merupakan halaman utama tempat pengguna dapat mengisi form registrasi. Dengan struktur ini, saat aplikasi dijalankan, pengguna langsung melihat form registrasi yang sudah dibuat di file user_registration_form.dart.

file 2: user_registration_form.dart


import 'package:flutter/material.dart';

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

  @override
  State createState() => _UserRegistrationFormState();
}

class _UserRegistrationFormState extends State {
  final _formKey = GlobalKey();
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _confirmPasswordController = TextEditingController();

  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Registrasi berhasil!')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Form Registrasi')),

      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
            
              TextFormField(
                controller: _nameController,
                decoration: const InputDecoration(labelText: 'Nama'),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Nama tidak boleh kosong';
                  }
                  return null;
                },
              ),

             
              TextFormField(
                controller: _emailController,
                decoration: const InputDecoration(labelText: 'Email'),
                keyboardType: TextInputType.emailAddress,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Email tidak boleh kosong';
                  }
                  if (!value.contains('@')) {
                    return 'Format email salah';
                  }
                  return null;
                },
              ),

             
              TextFormField(
                controller: _passwordController,
                decoration: const InputDecoration(labelText: 'Password'),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Password tidak boleh kosong';
                  }
                  if (value.length < 8) {
                    return 'Password minimal 8 karakter';
                  }
                  if (!RegExp(r'[A-Z]').hasMatch(value)) {
                    return 'Password harus mengandung setidaknya 1 huruf besar';
                  }
                  if (!RegExp(r'[0-9!@#\$&*~]').hasMatch(value)) {
                    return 'Password harus mengandung angka atau simbol';
                  }
                  return null;
                },
              ),

             
              TextFormField(
                controller: _confirmPasswordController,
                decoration: const InputDecoration(labelText: 'Konfirmasi Password'),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Konfirmasi password tidak boleh kosong';
                  }
                  if (value != _passwordController.text) {
                    return 'Password tidak sama';
                  }
                  return null;
                },
              ),

              const SizedBox(height: 20),

             
              ElevatedButton(
                onPressed: _submitForm,
                child: const Text('Submit'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
                  

Kode ini membuat sebuah form registrasi lengkap di Flutter menggunakan StatefulWidget. Form ini terdiri dari empat input: nama, email, password, dan konfirmasi password. Setiap input dikontrol oleh TextEditingController untuk mengambil dan mengelola nilai yang dimasukkan pengguna. Validasi diterapkan pada setiap field: nama dan email tidak boleh kosong, email harus mengandung karakter @, password harus minimal 8 karakter, mengandung huruf besar dan angka atau simbol, dan konfirmasi password harus sama dengan password. SingleChildScrollView digunakan agar form dapat digulir saat keyboard muncul, mencegah overflow. Saat tombol Submit ditekan, fungsi _submitForm() dijalankan, memeriksa validasi form, dan jika semua field valid, SnackBar muncul menampilkan pesan "Registrasi berhasil!".

untuk output ketika data diinputkan dengan benar, akan seperti ini

akan muncul pesan berhasil di bagian bawah

jika pada kolom email tidak sesuai format, akan muncul pesan error

jika input password dan konfirmasi tidak sama, akan muncul pesan error pada kolom password

jika input password tidak sesuai ketentuan, akan muncul juga pesan error

eaaaaa, gimana yahh