Tujuan praktikum ini yaitu mahasiswa mampu membuat membuat basic form untuk menerima inputan dari keyboard dan mengelola inputan :
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, selanjtunya data inputan akan diambil nilainya setelah proses pengecekan selesai dilakukan.
TextField adalah widget yang digunakan untuk memasukkan text oleh pengguna, widget ini biasanya digunakan untuk membuat form inputan seperti form login, pencarian dll.
Fitur Text Field:
TextFormField adalah widget versi lengkap dari TextField yang secara otomatis terintegrasi dengan logika validasi dan manajemen state dari sebuah form
Fitur TextFormField:
GlobalKey merupakan objek unik atau key yang digunakan untuk mengidentifikasi dan mengakses state secara global, artinya kita dapat mengakses widget dari widget mana saja.
FormState adalah kelas yang mengelola status dari Form, sepert status validasi setiap form inputan (TextFormField).
Menggunakan GlobalKey pada widget Form, maka kita dapat memanggil metode seperti validate() atau save() dari luar widget tersebut, biasanya dari onPressed pada ElevatedButton.
Metode validate() merupakan sebuah fungsi yang terdapat pada FormState yang digunakan untuk menjalankan validasi pada setiap TextFormField yang ada di dalam Form.
Ketika Anda memanggil _formKey.currentState!.validate(), maka Flutter akan:
setState merupakan sebuah method yang ada pada flutter, method ini digunakan untuk rebuild ulang state yang ada pada StatefulWidget atau secara sederhana method ini digunakan untuk memberitahu flutter bahwa state yang ada pada StatefulWidget telah berubah dan widget tersebut perlu untuk rebuild.
Kata kunci const pada widget Flutter digunakan untuk membuat widget menjadi konstanta pada saat kompilasi (compile-time). Penggunaan const dapat meningkatkan peforma karena widget const akan dibuat sekali dan akan disimpan pada memori sehingga dapat digunakan Kembali tanpa build ulang. Jika tidak menggunakan const maka widget akan di build() berkali-kali.
Dengan menggunakan kata kunci const maka flutter akan membangun / compile widget-widget tersebut sekali. Jika method build() dipanggil Kembali karena ada perubahan state pada widget lain maka widget yang sudah menggunakan kata kunci const tidak akan di rebuild sehingga proses reload lebih cepat dan menghemat sumber daya. Secara default flutter akan secara otomatis menjadikan widget menggunakan kata kunci const Ketika kode program disimpan.
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 {
final TextEditingController _teksEditingController = TextEditingController();
String inputText = '';
@override
void dispose() {
_teksEditingController.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 :',
style: TextStyle(fontSize: 16),
),
const SizedBox(height: 10),
TextField(
controller: _teksEditingController,
keyboardType: TextInputType.text,
onChanged: (text) {
print('Sedang mengetik teks : $text');
},
decoration: const InputDecoration(
labelText: 'Nama Lengkap',
hintText: 'Nama Lengkap',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.person),
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
String inputText = _teksEditingController.text;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Nama anda adalah $inputText!')),
);
setState(() {
inputText = _teksEditingController.text;
});
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.amber,
foregroundColor: Colors.black,
),
child: const Text('Tampilkan Nama'),
),
const SizedBox(height: 20),
Text(
'Nama Anda: ${_teksEditingController.text}',
style: const TextStyle(fontSize: 20)
),
],
)
);
}
}
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'),
),
),
],
),
),
);
}
}
Setelah melakukan praktikum membuat basic form menggunakan widget TextField dan TextFormField, silahkan kerjakan Tugas berikut 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('Kalkulator'),
),
body: const CalculatorForm(),
),
);
}
}
class CalculatorForm extends StatefulWidget {
const CalculatorForm({super.key});
@override
State createState() => _CalculatorFormState();
}
class _CalculatorFormState extends State {
final TextEditingController _controller1 = TextEditingController();
final TextEditingController _controller2 = TextEditingController();
String _hasil = '0';
void _hitung(String operasi) {
final double? angka1 = double.tryParse(_controller1.text);
final double? angka2 = double.tryParse(_controller2.text);
if (angka1 == null || angka2 == null) {
setState(() {
_hasil = 'Input tidak valid!';
});
return;
}
double? hasilPerhitungan;
switch (operasi) {
case 'kali':
hasilPerhitungan = angka1 * angka2;
break;
case 'bagi':
if (angka2 == 0) {
hasilPerhitungan = double.infinity;
} else {
hasilPerhitungan = angka1 / angka2;
}
break;
case 'tambah':
hasilPerhitungan = angka1 + angka2;
break;
case 'kurang':
hasilPerhitungan = angka1 - angka2;
break;
}
setState(() {
if (hasilPerhitungan != null) {
if (hasilPerhitungan.isInfinite) {
_hasil = 'Tidak terhingga';
} else {
_hasil = hasilPerhitungan.toString();
}
}
});
}
@override
void dispose() {
_controller1.dispose();
_controller2.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: _controller1,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'Angka Pertama',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 20),
TextField(
controller: _controller2,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'Angka Kedua',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(onPressed: () => _hitung('tambah'), child: const Text('+')),
ElevatedButton(onPressed: () => _hitung('kurang'), child: const Text('-')),
ElevatedButton(onPressed: () => _hitung('kali'), child: const Text('x')),
ElevatedButton(onPressed: () => _hitung('bagi'), child: const Text('/')),
],
),
const SizedBox(height: 30),
const Text(
'Hasil:',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
Text(
_hasil,
style: const TextStyle(fontSize: 24, color: Colors.blueAccent),
),
],
),
);
}
}