Laporan Praktikum 2 - Aplikasi Mobile
Pengenalan Widget dan Layouting
IF - Universitas Andalas
A. Pendahuluan
Pengenalan Widget
Untuk merancang aplikasi yang fungsional, widget diklasifikasikan menjadi dua jenis utama berdasarkan sifat datanya, yaitu Stateless Widget dan Stateful Widget. Stateless Widget adalah komponen statis yang tampilannya tidak pernah berubah setelah pertama kali dibangun (dirender) di layar. Karena tidak memiliki data internal yang berubah (State), widget ini bekerja lebih ringan dan cepat. Penggunaannya sangat cocok untuk elemen-elemen tetap seperti label teks, ikon, atau gambar statis. Di sisi lain, Stateful Widget merupakan komponen dinamis yang tampilannya dapat berubah-ubah sebagai respons terhadap interaksi pengguna atau adanya pembaruan data. Widget ini mampu menyimpan objek data internal dan akan memperbarui antarmuka pengguna secara otomatis ketika fungsi setState() dipanggil. Komponen seperti form input, checkbox, dan elemen animasi umumnya diimplementasikan menggunakan Stateful Widget.
Layouting dan Styling
Setelah memahami sifat komponen dasar, penyusunan widget di dalam layar memerlukan pemahaman tentang layouting dan styling. Flutter menyediakan berbagai widget tata letak, seperti Row yang merupakan widget untuk menyusun elemen secara menyamping (dari kiri ke kanan), serta Column yang merupakan widget untuk menyusun elemen secara menurun (dari atas ke bawah). Untuk membungkus komponen-komponen tersebut, digunakan Container, yaitu widget berbentuk kotak yang memungkinkan pengembang untuk mengatur margin, padding, dan batas (pembatas kotak).
List Tile
Selanjutnya, untuk mempermudah pembuatan elemen antarmuka berupa baris daftar, Flutter menyediakan widget bawaan dari Material Design yang disebut ListTile. ListTile secara instan menyusun elemen daftar dengan rapi dan terbagi menjadi tiga bagian utama: Leading yang berada di sisi paling kiri (biasanya diisi ikon atau avatar), Title yang merupakan area untuk teks judul utama, serta Trailing yang menempati posisi paling kanan dan sering dimanfaatkan untuk menampilkan angka nominal atau tombol aksi. Keseluruhan komponen layouting dan pengenalan state inilah yang menjadi fondasi dasar dalam merancang aplikasi interaktif menggunakan Flutter.
B. Tujuan Praktikum
Adapun tujuan dari pelaksanaan praktikum ini adalah sebagai berikut::
- Memahami kerangka dasar dalam pembuatan aplikasi Flutter, meliputi penggunaan MaterialApp dan Scaffold.
- Membedakan konsep serta penggunaan antara komponen Stateless Widget dan Stateful Widget.
- Menerapkan fungsi setState() untuk menghasilkan antarmuka pengguna (UI) yang interaktif.
- Menerapkan penggunaan widget Row untuk menyusun deretan tombol aksi secara menyamping.
- Menerapkan penggunaan widget Column untuk menyusun antarmuka berupa daftar transaksi secara menurun.
- Mengatur dan menerapkan padding, margin, serta pewarnaan pada widget Container.
C. Alat
Perangkat dan dependensi yang digunakan selama praktikum:
- Flutter SDK
- Code Editor : VS Code atau Android Studio.
- Emulator / Device
D. Langkah-langkah Praktikum
Modul 1
Praktikum diawali dengan membuat project baru menggunakan Flutter. Project dapat dibuat melalui VS Code atau Android Studio dengan memastikan Flutter SDK telah terpasang dan perangkat emulator atau device tersedia. Setelah project berhasil dibuat, file utama aplikasi yang digunakan dalam praktikum berada pada lib/main.dart. File tersebut menjadi titik awal untuk menjalankan aplikasi Flutter. Struktur dasar project Flutter digunakan untuk memisahkan kode aplikasi, konfigurasi, serta resource yang dibutuhkan. Pada praktikum ini, seluruh implementasi widget dibuat pada file main.dart agar konsep StatelessWidget, StatefulWidget, dan setState() dapat dipelajari secara langsung.
Langkah pertama pada kode adalah mengimpor library material.dart.
Kode tersebut digunakan untuk mengakses berbagai komponen dan fungsi Flutter berbasis Material Design. Dengan mengimpor material.dart, program dapat menggunakan widget seperti MaterialApp, Scaffold, AppBar, Text, Card, Column, Row, IconButton, dan CircleAvatar yang digunakan dalam praktikum.
Setelah library diimpor, aplikasi dijalankan melalui fungsi main().
Fungsi main() merupakan titik awal eksekusi program Flutter. Di dalamnya terdapat runApp() yang berfungsi menjalankan widget utama aplikasi. Pada kode tersebut, MyApp() digunakan sebagai widget utama dan dibuat dengan const karena widget tersebut tidak memiliki perubahan state secara langsung.
Method dispose() digunakan untuk membersihkan controller ketika widget sudah tidak digunakan. Pemanggilan _textEditingController.dispose() bertujuan untuk melepaskan resource yang digunakan oleh controller, kemudian super.dispose() menjalankan proses pembersihan dari parent class.
MyApp merupakan widget yang bersifat statis sehingga menggunakan StatelessWidget. Method build() digunakan untuk menentukan tampilan yang akan dibangun oleh Flutter. MaterialApp berfungsi sebagai struktur dasar aplikasi berbasis Material Design. Properti debugShowCheckedModeBanner: false digunakan untuk menghilangkan tulisan DEBUG pada pojok aplikasi, sedangkan title memberikan nama aplikasi. Bagian theme menentukan tema utama aplikasi, sementara home menentukan halaman pertama yang ditampilkan, yaitu DashboardScreen.
Setelah widget utama dibuat, halaman utama aplikasi didefinisikan menggunakan Scaffold.
DashboardScreen juga menggunakan StatelessWidget karena halaman tersebut tidak menyimpan perubahan state secara langsung. Scaffold menyediakan struktur dasar halaman, seperti AppBar dan body. Pada bagian AppBar, ditampilkan judul "Praktikum 1: Widgets" dengan warna biru.
Bagian body menggunakan Padding untuk memberikan jarak antara isi aplikasi dengan tepi layar. Di dalamnya terdapat Column yang menyusun widget secara vertikal. GreetingWidget() digunakan untuk menampilkan sapaan pengguna, sedangkan SizedBox memberikan jarak vertikal sebesar 20 pixel sebelum BalanceCardWidget() ditampilkan.
Setelah widget utama dibuat, halaman utama aplikasi didefinisikan menggunakan Scaffold.
GreetingWidget digunakan untuk menampilkan informasi sapaan yang bersifat statis. Row digunakan untuk menyusun elemen secara horizontal, yaitu avatar dan teks. CircleAvatar digunakan sebagai ikon profil, sedangkan SizedBox memberikan jarak antara avatar dan teks.
Teks sapaan disusun menggunakan Column agar dua teks dapat ditampilkan secara vertikal. Teks pertama menampilkan "Halo, Budi" dengan ukuran lebih besar dan tebal, sedangkan teks kedua menampilkan "Selamat datang kembali!" dengan ukuran lebih kecil dan warna abu-abu. Karena informasi tersebut tidak berubah selama aplikasi berjalan, widget ini sesuai dibuat menggunakan StatelessWidget.
Berbeda dengan widget sapaan, kartu saldo harus dapat merespons interaksi pengguna ketika ikon mata ditekan. Oleh karena itu, kartu saldo dibuat menggunakan StatefulWidget.
BalanceCardWidget menggunakan StatefulWidget karena tampilannya dapat berubah berdasarkan kondisi tertentu. Method createState() digunakan untuk membuat objek state yang akan mengatur perubahan pada widget tersebut. Pada praktikum ini, perubahan terjadi ketika pengguna menekan tombol mata untuk menampilkan atau menyembunyikan nominal saldo.
State dari kartu saldo didefinisikan pada _BalanceCardWidgetState.
Variabel _isBalanceVisible digunakan untuk menyimpan kondisi apakah saldo sedang ditampilkan atau disembunyikan. Tipe datanya adalah bool, sehingga hanya memiliki dua kemungkinan nilai, yaitu true dan false.
Nilai awalnya adalah true, sehingga ketika aplikasi pertama kali dijalankan, nominal saldo akan terlihat. Variabel ini merupakan state karena nilainya dapat berubah akibat interaksi pengguna.
Perubahan nilai state dilakukan melalui fungsi _toggleVisibility().
Fungsi tersebut menggunakan setState() untuk memberi tahu Flutter bahwa terdapat perubahan data yang memengaruhi tampilan. Operator ! digunakan untuk membalik nilai boolean. Jika _isBalanceVisible bernilai true, nilainya akan berubah menjadi false, begitu juga sebaliknya.
Dengan adanya setState(), Flutter akan membangun kembali bagian UI yang berkaitan dengan state tersebut sehingga tampilan saldo dapat berubah secara langsung setelah tombol ditekan.
Tampilan kartu saldo dibuat menggunakan Card.
Card digunakan sebagai wadah informasi saldo. Properti elevation memberikan efek bayangan sehingga kartu terlihat lebih menonjol. RoundedRectangleBorder dengan BorderRadius.circular(16) digunakan untuk membuat sudut kartu menjadi melengkung. Warna awal kartu adalah Colors.blueAccent.
Padding memberikan ruang di bagian dalam kartu agar isi tidak terlalu dekat dengan batas kartu. Kemudian Column digunakan untuk menyusun elemen kartu secara vertikal.
Row digunakan agar teks "Saldo Utama" dan tombol mata berada pada satu baris. MainAxisAlignment.spaceBetween membuat kedua elemen berada di sisi yang berlawanan. IconButton digunakan sebagai tombol yang dapat ditekan pengguna.
Icon yang digunakan bergantung pada nilai _isBalanceVisible. Jika bernilai true, icon yang ditampilkan adalah Icons.visibility, sedangkan jika bernilai false, icon berubah menjadi Icons.visibility_off. Ketika tombol ditekan, fungsi _toggleVisibility dijalankan untuk mengubah state.
Nominal saldo ditampilkan menggunakan widget Text.
SizedBox memberikan jarak antara bagian judul kartu dan nominal saldo. Selanjutnya, Text menampilkan nominal saldo berdasarkan nilai _isBalanceVisible.
ada bagian ini digunakan ternary operator untuk membuat kondisi sederhana. Jika _isBalanceVisible bernilai true, aplikasi menampilkan Rp 5.000.000. Jika bernilai false, aplikasi menampilkan **Rp ***********. Dengan demikian, pengguna dapat menyembunyikan atau menampilkan nominal saldo menggunakan tombol mata.
Setelah seluruh kode ditulis, aplikasi dijalankan menggunakan browser. Ketika aplikasi berhasil dijalankan, halaman utama menampilkan AppBar, sapaan pengguna, dan kartu saldo.
Pada kondisi awal, nominal saldo ditampilkan karena _isBalanceVisible memiliki nilai true. Ketika ikon mata ditekan, _toggleVisibility() akan dipanggil. Fungsi tersebut mengubah nilai state dan Flutter melakukan render ulang sehingga nominal berubah menjadi bentuk tersensor. Ketika tombol ditekan kembali, saldo akan ditampilkan lagi.
Hasil tersebut menunjukkan penerapan StatelessWidget pada komponen yang bersifat statis dan StatefulWidget pada komponen yang membutuhkan perubahan tampilan.
Modul 2
Melanjutkan dari Modul 1, dan masih di file main.dart
Modul 2 merupakan lanjutan dari Modul 1. Project Flutter yang telah dibuat pada Modul I tetap digunakan, kemudian kode pada lib/main.dart diperbarui untuk menambahkan komponen layout dan styling baru. Pada modul ini, komponen dari Modul I seperti GreetingWidget dan BalanceCardWidget tetap digunakan, kemudian ditambahkan widget tombol aksi dan daftar transaksi.
Dikarenakan file yang digunakan masih sama dengan modul 1 yaitu main.dart, kita fokus ke perubahan yang dilakukan. Langsung saja lompat ke membuat halaman utama menggunakan widget Scaffold.
Pada Modul II, halaman utama diperbarui dengan menambahkan SingleChildScrollView.
Scaffold digunakan sebagai struktur utama halaman. Pada AppBar, judul diubah menjadi "Praktikum 2: Layouting". Bagian body menggunakan SingleChildScrollView agar seluruh isi halaman dapat digulir ketika jumlah konten melebihi tinggi layar. Hal ini penting karena Modul II menambahkan tombol aksi dan beberapa transaksi sehingga konten menjadi lebih panjang dibandingkan Modul I.
Di dalam SingleChildScrollView terdapat Padding dengan nilai 16.0 untuk memberikan jarak dari tepi layar. Selanjutnya digunakan Column untuk menyusun seluruh komponen secara vertikal. Komponen yang digunakan adalah GreetingWidget dan BalanceCardWidget dari Modul I, kemudian ActionButtonsWidget dan RecentTransactionsWidget sebagai komponen baru dari Modul II. Modul secara khusus menginstruksikan agar komponen Modul I dan Modul II digabungkan dan dibungkus dengan SingleChildScrollView untuk mencegah overflow ketika daftar transaksi bertambah panjang.
Widget sapaan dari Modul I tetap digunakan pada Modul II.
GreetingWidget masih menggunakan StatelessWidget karena isi sapaan bersifat statis. Row digunakan untuk menyusun ikon profil dan teks secara horizontal, sedangkan Column digunakan untuk menumpuk teks sapaan dan teks sambutan secara vertikal. Widget ini menjadi salah satu komponen yang digunakan kembali dari Modul I pada dashboard Modul II.
Widget kartu saldo dari Modul I juga tetap digunakan pada Modul II.
BalanceCardWidget tetap menggunakan StatefulWidget karena nominal saldo dapat berubah antara kondisi terlihat dan tersensor. Variabel _isBalanceVisible menyimpan kondisi saldo, sedangkan _toggleVisibility() menggunakan setState() untuk mengubah kondisi tersebut. Dengan demikian, fitur interaktif dari Modul I tetap dapat digunakan pada dashboard Modul II. Struktur kartu menggunakan Card, Padding, Column, dan Row untuk mengatur tampilan elemen di dalam kartu.
Komponen baru pertama pada Modul II adalah ActionButtonsWidget.
ActionButtonsWidget menggunakan Row untuk menyusun tiga tombol secara horizontal, yaitu Pemasukan, Pengeluaran, dan Transfer. Properti mainAxisAlignment diatur menggunakan spaceEvenly sehingga ruang kosong di antara dan di sekitar tombol dibagi secara merata.
Agar kode tidak perlu ditulis berulang kali untuk setiap tombol, digunakan fungsi pembantu _buildActionButton().
Fungsi _buildActionButton() menerima tiga parameter, yaitu icon untuk menentukan ikon, label untuk menentukan teks tombol, dan color untuk menentukan warna. Fungsi ini menghasilkan Column yang berisi Container dan teks label.Fungsi _buildActionButton() menerima tiga parameter, yaitu icon untuk menentukan ikon, label untuk menentukan teks tombol, dan color untuk menentukan warna. Fungsi ini menghasilkan Column yang berisi Container dan teks label.
Container digunakan untuk membungkus ikon sekaligus mengatur tampilan latar belakangnya. Properti padding memberikan ruang di sekitar ikon, sedangkan BoxDecoration digunakan untuk memberikan warna latar belakang transparan dan sudut yang melengkung. color.withOpacity(0.2) membuat warna background menjadi lebih transparan dibandingkan warna ikon.
Komponen baru berikutnya adalah RecentTransactionsWidget.
Widget ini menggunakan Column karena transaksi disusun secara vertikal. Bagian awal widget menampilkan judul "Transaksi Terakhir", kemudian diberikan jarak menggunakan SizedBox.
Daftar transaksi dibungkus menggunakan Card.
Card digunakan sebagai wadah agar seluruh daftar transaksi terlihat seperti satu kelompok. elevation: 2 memberikan efek bayangan, sedangkan RoundedRectangleBorder membuat sudut kartu menjadi melengkung. Di dalam Card terdapat Column yang digunakan untuk menempatkan beberapa ListTile secara vertikal.
Transaksi pertama adalah Makan Siang.
ListTile digunakan untuk membuat satu baris transaksi dengan struktur yang rapi. Bagian leading berisi ikon yang ditempatkan di sebelah kiri, title berisi nama transaksi, subtitle berisi tanggal transaksi, sedangkan trailing berisi nominal transaksi di sebelah kanan. Lalu ditambahkan Garis Pemisah antara transaksi pertama dan transaksi berikutnya.
Transaksi kedua adalah Gaji Bulanan.
Struktur transaksi kedua sama dengan transaksi pertama, tetapi digunakan untuk merepresentasikan pemasukan. Ikon menggunakan Icons.attach_money, sedangkan nominal diawali tanda +. Hal tersebut membuat jenis transaksi dapat dibedakan secara visual.
Transaksi ketiga adalah Isi Bensin.
Transaksi ketiga juga menggunakan ListTile. Ikon Icons.directions_car digunakan untuk menggambarkan transaksi pengisian bahan bakar. Nominal menggunakan tanda minus karena termasuk transaksi pengeluaran.
Setelah seluruh widget selesai dibuat, aplikasi dijalankan menggunakan emulator atau device. Dashboard akan menampilkan komponen dari Modul I dan Modul II secara berurutan, yaitu sapaan pengguna, kartu saldo, tombol aksi, dan daftar transaksi.
Pada bagian tombol aksi, tiga tombol ditampilkan secara horizontal menggunakan Row. Selanjutnya daftar transaksi ditampilkan secara vertikal menggunakan Column dan beberapa ListTile. Karena seluruh konten dibungkus SingleChildScrollView, halaman dapat digulir apabila konten tidak seluruhnya muat pada layar. Hasil akhir praktikum berupa mockup dashboard yang menggabungkan konsep layouting dan styling dari Modul II dengan komponen Modul I.
Latihan - Modul 1
Ada dua latihan, yaitu mengubah warna BalanceCard dari biru menjadi hijau emerald menggunakan Colors.teal, serta menambahkan teks "No. Rekening: 1234-5678" di bawah nominal saldo.
Latihan 1: Styling Mengubah warna BalanceCard dari biru menjadi hijau emerald menggunakan Colors.teal.
Pada kode awal, warna kartu saldo ditentukan oleh: color: Colors.blueAccent,
Kode tersebut membuat latar belakang BalanceCardWidget menggunakan warna biru blueAccent.
Kode setelah perubahanSesuai instruksi latihan, warna kartu saldo ditentukan oleh: color: Colors.teal,
Kode tersebut membuat latar belakang BalanceCardWidget menggunakan warna hijau emerald.
Hasil perubahan
Setelah kode diubah, aplikasi dijalankan dan tampilan kartu saldo berubah dari biru menjadi hijau emerald.
Latihan 2: Modifikasi UI Menambahkan teks "No. Rekening: 1234-5678" di bawah nominal saldo.
Pada latihan kedua, ditambahkan teks statis "No. Rekening: 1234-5678" di bagian bawah nominal saldo. Karena teks tersebut bersifat statis, tidak diperlukan state baru untuk menampilkannya.
Kode sebelum perubahanBagian akhir kartu pada kode awal adalah:
Kode tersebut hanya menampilkan nominal saldo berdasarkan kondisi _isBalanceVisible.
Menambahkan teks nomor rekeningMenambahkan widget Text, lalu agar nomor rekening tidak terlalu dekat dengan nominal saldo, ditambahkan SizedBox.
Kode tersebut menghasilkan teks statis "No. Rekening: 1234-5678". Kata kunci const digunakan karena isi teks dan tampilannya tidak berubah selama aplikasi berjalan. Ukuran font dibuat lebih kecil dibandingkan nominal saldo agar hierarki informasi tetap jelas, sedangkan Colors.white70 digunakan agar teks terlihat lebih ringan.
Lalu SizedBox ditambahkan untuk memberikan jarak antara teks nomor rekening dan nominal saldo.
Hasil perubahan
Setelah modifikasi, kartu saldo akan menampilkan nominal saldo dan nomor rekening pada bagian bawahnya. Nominal saldo tetap dapat ditampilkan atau disembunyikan menggunakan tombol mata, sedangkan nomor rekening akan tetap terlihat karena merupakan informasi statis.
Latihan - Modul 2
Latihan 1: Styling Pada widget Daftar Transaksi (ListTile), ubah warna trailing text pengeluaran menjadi merah dan text pemasukan menjadi hijau.
Untuk transaksi pengeluaran seperti Makan Siang, kode trailing menggunakan warna merah.
Properti trailing digunakan untuk menampilkan nominal pada sisi kanan ListTile. Karena transaksi merupakan pengeluaran, nominal diberi tanda minus dan warna merah. fontWeight: FontWeight.bold digunakan agar nominal lebih mudah terlihat.
Hal yang sama diterapkan pada transaksi Isi Bensin:
Untuk Bagian Pemasukan
Untuk transaksi pemasukan seperti Gaji Bulanan, warna nominal menggunakan hijau.
Tanda + menunjukkan bahwa transaksi tersebut merupakan pemasukan. Warna hijau digunakan untuk membedakannya dari transaksi pengeluaran yang menggunakan warna merah.
Hasil perubahan
Dengan dilakukan pengaturan tersebut, transaksi pengeluaran akan memiliki nominal berwarna merah, sedangkan transaksi pemasukan memiliki nominal berwarna hijau.
Latihan 2: Tambah Data Menambahkan 2 transaksi fiktif baru ke dalam daftar "Transaksi Terakhir" di bawah kode yang sudah ada.
Latihan kedua meminta penambahan dua transaksi fiktif baru ke dalam daftar "Transaksi Terakhir" di bawah transaksi yang sudah tersedia.
Transaksi baru pertama adalah "Top Up Game" dengan nominal pengeluaran Rp 300.000, sedangkan transaksi baru kedua adalah "Bonus Lembur" dengan nominal pemasukan Rp 750.000.
Kedua transaksi baru ditempatkan setelah ListTile transaksi ketiga dan masih berada di dalam Column pada Card.
Menambahkan Transaksi Fiktif PertamaKode berikut digunakan untuk menambahkan transaksi Top Up Game:
Transaksi ini menggunakan ikon Icons.sport_esport untuk menggambarkan aktivitas gaming. Karena merupakan pengeluaran, nominal diawali tanda minus dan menggunakan warna merah. Divider ditambahkan sebelum transaksi agar terdapat garis pemisah dengan transaksi sebelumnya.
Menambahkan Transaksi Fiktif KeduaTransaksi berikutnya adalah Bonus Lembur.
Transaksi ini menggunakan ikon Icons.attach_money sebagai representasi bonus. Karena merupakan pemasukan, nominal menggunakan tanda + dan warna hijau.
Hasil perubahan
Setelah modifikasi, kartu saldo akan menampilkan nominal saldo dan nomor rekening pada bagian bawahnya. Nominal saldo tetap dapat ditampilkan atau disembunyikan menggunakan tombol mata, sedangkan nomor rekening akan tetap terlihat karena merupakan informasi statis.
E. Kesimpulan
Berdasarkan praktikum yang telah dilaksanakan, dapat disimpulkan bahwa pembangunan antarmuka aplikasi menggunakan kerangka kerja Flutter sangat bergantung pada pemahaman tentang jenis komponen (widget) dan dasar manajemen state. Penggunaan Stateless Widget sangat tepat dan efisien untuk membangun elemen antarmuka yang bersifat statis atau tidak mengalami perubahan data setelah dirender, seperti pada pembuatan komponen sapaan pengguna. Sebaliknya, penerapan Stateful Widget terbukti sangat esensial untuk menciptakan komponen yang dinamis dan interaktif. Melalui pemanfaatan fungsi setState(), aplikasi mampu merekam perubahan data internal dan merender ulang sebagian tampilan antarmuka secara instan sebagai respons terhadap interaksi pengguna, yang dipraktikkan langsung pada fitur sembunyikan dan tampilkan nominal di kartu saldo.
Selain penguasaan state, pengaturan tata letak (layouting) dan visual (styling) menjadi fondasi penting dalam membangun desain antarmuka yang rapi dan terstruktur. Penggunaan widget Row sangat efektif untuk menata elemen secara menyamping seperti pada deretan tombol aksi, sedangkan kombinasi Column dan ListTile mempermudah penyusunan elemen bersusun yang memanjang ke bawah seperti pada daftar riwayat transaksi. Integrasi seluruh komponen dari kedua modul tersebut beserta penambahan elemen hasil penugasan latihan yang dibungkus secara menyeluruh ke dalam widget SingleChildScrollView, memastikan aplikasi memiliki kapabilitas scroll vertikal. Hal ini menjamin antarmuka layar terhindar dari masalah konten terpotong (overflow), sehingga menghasilkan aplikasi pencatat keuangan yang fungsional dan estetis.