Kembali ke Laporan

Laprak 2 — Widgets, Layouting & Styling (Flutter)

Aplikasi Mobile · Pertemuan 2

Saskia Alifah 2411531002 Aplikasi Mobile Flutter Row, Column, Container & ListTile
Daftar Isi

Pertemuan ini terdiri dari dua modul yang saling berkelanjutan. Modul 1 bertujuan agar mahasiswa memahami kerangka dasar aplikasi Flutter melalui MaterialApp dan Scaffold, mampu membedakan penggunaan StatelessWidget dan StatefulWidget, serta mampu menerapkan fungsi setState() untuk membangun UI yang interaktif — dicontohkan lewat kartu saldo yang dapat disembunyikan dan ditampilkan kembali.

Modul 2 melanjutkan dashboard yang sudah dibuat pada Modul 1 dengan menambahkan kemampuan layouting yang lebih kompleks: menerapkan widget Row untuk menyusun deretan tombol aksi, menerapkan widget Column untuk menyusun daftar transaksi menggunakan ListTile, serta mengatur padding, margin, dan warna pada Container agar tampilan lebih rapi dan enak dilihat.

Stateless Widget adalah widget statis yang tampilannya tidak pernah berubah setelah dirender di layar, karena tidak memiliki data internal (state) yang dapat berubah. Widget jenis ini lebih ringan dan cepat, dan cocok dipakai untuk elemen seperti label teks, ikon, atau gambar statis — contohnya GreetingWidget pada dashboard ini.

Stateful Widget sebaliknya adalah widget dinamis yang tampilannya dapat berubah sebagai respons terhadap interaksi pengguna atau data baru. Widget ini menyimpan objek data internal (State) dan dapat merender ulang UI melalui setState(). Untuk membuatnya, dibutuhkan dua class: satu yang meng-extend StatefulWidget dan satu lagi yang meng-extend State<T>, tempat seluruh logika dan variabel state sebenarnya disimpan.

setState() adalah method yang memberi tahu Flutter bahwa ada perubahan data pada state, sehingga build() perlu dipanggil ulang agar tampilan disinkronkan dengan data terbaru. Tanpa memanggil setState(), perubahan pada variabel biasa tidak akan pernah terlihat di layar meskipun nilainya sudah berubah di balik layar.

Row dan Column adalah dua widget layouting dasar pada Flutter. Row menyusun elemen anaknya secara horizontal (menyamping kiri ke kanan), sedangkan Column menyusun elemen anaknya secara vertikal (menurun atas ke bawah). Properti mainAxisAlignment mengatur jarak antar elemen pada sumbu utama — misalnya nilai spaceEvenly membagi ruang kosong yang tersisa secara merata di antara dan di sekitar setiap elemen.

Container adalah widget serbaguna yang berfungsi sebagai "kotak" pembungkus, dilengkapi properti padding (jarak dari tepi kotak ke isinya), margin (jarak dari kotak ke elemen di luarnya), serta decoration untuk mengatur warna latar, sudut membulat, hingga border.

ListTile adalah widget bawaan Material Design yang memudahkan pembuatan baris daftar secara instan tanpa perlu menyusun Row/Column manual. ListTile memiliki tiga slot utama: leading untuk elemen paling kiri (biasanya ikon atau avatar), title untuk judul utama baris, dan trailing untuk elemen paling kanan (biasanya nominal atau tombol) — kombinasi inilah yang dipakai untuk menampilkan tiap baris pada daftar "Transaksi Terakhir".

  • Laptop / Komputer dengan Flutter SDK dan Dart terinstall
  • Visual Studio Code (Code Editor) dengan ekstensi Flutter & Dart
  • Chrome Browser / Android Emulator sebagai target device untuk menjalankan aplikasi
  • Modul Praktikum Aplikasi Mobile — Praktikum 1: Pengenalan Widgets dan Praktikum 2: Layouting & Styling
Modul 1

Modul 1 membangun dashboard versi awal berisi dua widget: GreetingWidget sebagai sapaan pengguna (Stateless) dan BalanceCardWidget sebagai kartu saldo yang bisa disembunyikan/ditampilkan (Stateful).

D.1 lib/main.dart — Langkah Praktikum
1Membangun Struktur Dasar Aplikasi

Langkah pertama adalah membangun kerangka aplikasi. MyApp dijadikan root widget berupa StatelessWidget yang mengembalikan MaterialApp dengan tema warna Colors.blue, lalu DashboardScreen menyediakan Scaffold berisi AppBar berjudul "Praktikum 1: Widgets" dan body berupa Padding + Column yang akan diisi GreetingWidget dan BalanceCardWidget.

Aksi: Jalankan main.dart dan Lihat Struktur Awal
SS VS Code struktur MyApp, MaterialApp, Scaffold pada main.dart Modul 1
Gambar D.1a – Struktur dasar MyApp dengan tema Colors.blue dan Scaffold berjudul "Praktikum 1: Widgets"
Penjelasan Kode

void main() => runApp(const MyApp()) adalah titik masuk aplikasi. MyApp cukup mengembalikan MaterialApp(theme: ThemeData(primarySwatch: Colors.blue), home: const DashboardScreen()), sehingga seluruh komponen Material Design pada aplikasi mengikuti palet warna biru secara konsisten.

Pada DashboardScreen, body dibungkus Padding(padding: EdgeInsets.all(16.0)) agar konten tidak menempel ke tepi layar, lalu Column(crossAxisAlignment: CrossAxisAlignment.start, children: [GreetingWidget(), SizedBox(height: 20), BalanceCardWidget()]) menyusun kedua widget secara vertikal dengan jarak 20 piksel di antaranya.

2Membuat GreetingWidget (Stateless)

GreetingWidget dibuat sebagai StatelessWidget karena tampilan sapaan tidak pernah berubah. Widget ini memakai Row untuk meletakkan CircleAvatar berisi ikon orang di sisi kiri, lalu Column di sebelahnya untuk menumpuk dua baris teks: nama pengguna dan sub-teks sapaan.

Aksi: Susun Row + CircleAvatar + Column pada GreetingWidget
SS VS Code widget GreetingWidget dengan Row CircleAvatar dan Column teks sapaan
Gambar D.1b – GreetingWidget menyusun CircleAvatar dan Column teks "Halo, Saskia" / "Selamat datang kembali!" dalam satu Row
Penjelasan Kode

CircleAvatar(radius: 24, backgroundColor: Colors.blueAccent, child: Icon(Icons.person, ...)) membuat lingkaran avatar berwarna biru berisi ikon orang. SizedBox(width: 12) memberi jarak horizontal ke teks di sebelahnya, lalu Column(crossAxisAlignment: CrossAxisAlignment.start, children: [Text('Halo, Saskia', ...), Text('Selamat datang kembali!', ...)]) menumpuk dua teks rata kiri — nama dengan font tebal berukuran 20, dan sub-teks berwarna abu-abu berukuran 14. //

3Mendeklarasikan BalanceCardWidget sebagai Stateful

Karena kartu saldo harus bisa bereaksi saat ikon mata ditekan, BalanceCardWidget wajib dibuat sebagai StatefulWidget. Class _BalanceCardWidgetState menyimpan variabel bool _isBalanceVisible = true sebagai status sensor saldo, beserta method _toggleVisibility() yang akan membalik nilai boolean tersebut.

Aksi: Buat StatefulWidget dan Variabel _isBalanceVisible
SS VS Code deklarasi StatefulWidget BalanceCardWidget dan variabel isBalanceVisible
Gambar D.1c – Deklarasi class BalanceCardWidget beserta _BalanceCardWidgetState dan variabel _isBalanceVisible
Penjelasan Kode

State<BalanceCardWidget> createState() => _BalanceCardWidgetState(); menghubungkan widget dengan class state-nya. Di dalam _BalanceCardWidgetState, variabel _isBalanceVisible bertindak sebagai penanda apakah nominal saldo sedang ditampilkan (true) atau disensor (false), sedangkan _toggleVisibility() memanggil setState(() { _isBalanceVisible = !_isBalanceVisible; }) untuk membalik nilainya sekaligus memberi tahu Flutter agar merender ulang widget.

4Menyusun Card dan Baris Atas (Saldo Utama + Tombol Mata)

Isi kartu dibungkus Card berwarna Colors.blueAccent dengan sudut membulat, lalu di dalamnya Padding dan Column menyusun baris atas berupa Row dengan mainAxisAlignment: MainAxisAlignment.spaceBetween agar teks "Saldo Utama" menempel kiri dan IconButton ikon mata menempel kanan.

Aksi: Susun Card, Row spaceBetween, dan IconButton
SS VS Code Card BalanceCardWidget dengan Row spaceBetween teks Saldo Utama dan IconButton
Gambar D.1d – Card biru dengan Row spaceBetween berisi teks "Saldo Utama" dan IconButton ikon mata
Penjelasan Kode

IconButton(icon: Icon(_isBalanceVisible ? Icons.visibility : Icons.visibility_off, color: Colors.white), onPressed: _toggleVisibility) menampilkan ikon mata terbuka saat saldo terlihat dan ikon mata tercoret saat saldo disensor, memakai ternary operator untuk memilih ikon secara dinamis berdasarkan nilai _isBalanceVisible. Setiap tombol ditekan, onPressed memanggil _toggleVisibility yang sudah dibuat pada langkah sebelumnya.

5Menampilkan Nominal Saldo dengan setState() & Ternary

Nominal saldo ditampilkan lewat Text(_isBalanceVisible ? 'Rp 5.000.000' : 'Rp *********', ...). Setiap kali _toggleVisibility() dipanggil dan setState() dijalankan, Flutter merender ulang build() sehingga teks ini otomatis berpindah antara nominal asli dan versi tersensor tanpa perlu logika tambahan.

Aksi: Tambahkan Text Ternary untuk Nominal Saldo
SS VS Code Text ternary menampilkan Rp 5.000.000 atau Rp sensor pada BalanceCardWidget
Gambar D.1e – Kode Text dengan ternary operator yang berpindah antara nominal saldo asli dan versi tersensor
Penjelasan Kode

Logika ternary kondisi ? nilaiJikaTrue : nilaiJikaFalse dipakai di sini sebagai cara singkat menulis if-else dalam satu baris ekspresi, cocok dipakai langsung di dalam widget Text tanpa perlu variabel tambahan atau method terpisah.

6Menjalankan dan Menguji Toggle Visibilitas Saldo

Aplikasi dijalankan lalu diuji dengan menekan ikon mata pada kartu saldo untuk membuktikan bahwa setState() benar-benar memicu perubahan tampilan secara langsung (realtime), baik pada teks nominal maupun ikon itu sendiri.

Pengujian: Tekan Ikon Mata untuk Menyembunyikan dan Menampilkan Saldo
Percobaan: Kondisi Awal (Saldo Terlihat) vs Setelah Ikon Mata Ditekan (Saldo Disensor)
SS hasil running main.dart Modul 1 saldo terlihat Rp 5.000.000 ikon mata terbuka
Gambar D.1f – Kondisi awal: saldo tampil "Rp 5.000.000" dengan ikon mata terbuka (Icons.visibility)
SS hasil running main.dart Modul 1 saldo tersensor Rp bintang ikon mata tercoret setelah ditekan
Gambar D.1g – Setelah ikon mata ditekan: saldo berubah menjadi "Rp *********" dan ikon berubah jadi tercoret (Icons.visibility_off)
Ikon mata berhasil membalik status sensor saldo setiap kali ditekan berulang kali secara bolak-balik, menandakan setState() pada BalanceCardWidget berjalan dengan benar.
D.2 Tugas Praktikum 1
Tugas 1 & 2 — Modul 1

Tugas 1 (Styling): mengubah warna tema BalanceCard dari biru (Colors.blueAccent) menjadi hijau emerald (Colors.teal). Tugas 2 (Modifikasi UI): menambahkan teks statis "No. Rekening: 1234-5678" di bagian bawah nominal saldo di dalam kartu.

1Tugas 1: Mengganti Warna Tema BalanceCard menjadi Teal

Warna Colors.blueAccent pada Card diganti menjadi gradasi Colors.teal. Agar transisi warnanya lebih halus dibanding warna solid, Card dibungkus tambahan Container dengan BoxDecoration(gradient: LinearGradient(colors: [Colors.teal.shade400, Colors.teal.shade700])), serta ThemeData(primarySwatch: Colors.teal) pada MyApp agar warna AppBar ikut menyesuaikan.

Aksi: Ganti primarySwatch dan Warna Card menjadi Teal (Gradient)
SS VS Code kode LinearGradient Colors.teal menggantikan Colors.blueAccent pada Card BalanceCardWidget
Gambar D.2a – BoxDecoration dengan LinearGradient Colors.teal.shade400 ke Colors.teal.shade700 menggantikan warna solid blueAccent
Penjelasan Kode

Sebelum: Card langsung diberi color: Colors.blueAccent sebagai warna solid, dan tema aplikasi pada MyApp memakai ThemeData(primarySwatch: Colors.blue).

Sesudah: properti color pada Card dihapus, lalu Card diberi child: Container(...) tambahan dengan decoration: BoxDecoration(gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Colors.teal.shade400, Colors.teal.shade700])), sehingga kartu tampil gradasi dari teal muda ke teal tua, bukan lagi warna solid tunggal. Dua penyesuaian lain juga ditambahkan agar warna konsisten di seluruh aplikasi:

  • ThemeData(primarySwatch: Colors.blue) diubah menjadi ThemeData(primarySwatch: Colors.teal) pada MyApp, sehingga AppBar dan komponen Material lain ikut berubah ke teal.
  • shadowColor: Colors.teal.withOpacity(0.4) ditambahkan pada Card agar bayangan yang dihasilkan senada dengan warna kartu, bukan lagi bayangan abu-abu default.
Hasil: Tampilan Card Berubah Warna Menjadi Teal
SS hasil running Tugas 1 Modul 1 kartu saldo berwarna gradasi teal
Gambar D.2b – Kartu saldo tampil dengan gradasi warna teal menggantikan warna biru solid sebelumnya, membuktikan perubahan pada BoxDecoration dan primarySwatch berhasil diterapkan
2Tugas 2: Menambahkan Teks Nomor Rekening

Di bawah nominal saldo, ditambahkan Divider tipis sebagai pemisah, lalu Row berisi Icon(Icons.credit_card) dan Text('No. Rekening: 1234-5678') memakai variabel final String _noRekening = '1234-5678' yang disisipkan lewat string interpolation 'No. Rekening: $_noRekening'.

Aksi: Tambahkan Divider, Icon, dan Text Nomor Rekening
SS VS Code Row Icon credit_card dan Text No Rekening 1234-5678 ditambahkan di bawah nominal saldo
Gambar D.2c – Divider, Icon credit_card, dan Text "No. Rekening: 1234-5678" ditambahkan di bagian bawah nominal saldo
Penjelasan Kode

Sebelum: Column pada BalanceCardWidget berhenti setelah widget Text nominal saldo — tidak ada elemen lain di bawahnya.

Sesudah: ditambahkan dua variabel baru pada _BalanceCardWidgetState, yaitu final String _balance = 'Rp 5.000.000' dan final String _noRekening = '1234-5678', lalu di bawah Text nominal saldo ditambahkan empat widget baru secara berurutan:

  • SizedBox(height: 12) — jarak vertikal tambahan dari nominal saldo.
  • Divider(color: Colors.white24, height: 1) — garis pemisah tipis semi-transparan.
  • Row(children: [Icon(Icons.credit_card, ...), SizedBox(width: 6), Text('No. Rekening: $_noRekening', ...)]) — baris berisi ikon kartu kredit dan teks nomor rekening, dengan nilai _noRekening disisipkan lewat string interpolation.
Hasil: Nomor Rekening Tampil di Bawah Nominal Saldo
SS hasil running Tugas 2 Modul 1 teks No Rekening 1234-5678 tampil pada kartu saldo teal
Gambar D.2d – Teks "No. Rekening: 1234-5678" berhasil tampil di bawah nominal saldo, sesuatu yang sebelumnya tidak ada pada versi Card
Kedua tugas berjalan sesuai ekspektasi: warna kartu sepenuhnya berpindah ke teal dan teks nomor rekening tampil statis tanpa mengganggu fungsi toggle visibilitas saldo yang sudah dibuat sebelumnya.
Modul 2

Modul 2 melanjutkan dashboard dari Modul 1 (lengkap dengan hasil Tugas 1 & 2 di atas) dengan menambahkan ActionButtonsWidget (Row) dan RecentTransactionsWidget (Column + ListTile), lalu membungkus seluruh dashboard dengan SingleChildScrollView agar layar tidak overflow saat daftar transaksi bertambah panjang.

E.1 lib/main.dart — Langkah Praktikum
1Menyusun Tombol Aksi dengan Row

ActionButtonsWidget dibuat sebagai StatelessWidget yang mengembalikan Row berisi tiga tombol aksi: Pemasukan, Pengeluaran, dan Transfer, disusun sejajar secara horizontal menggunakan mainAxisAlignment: MainAxisAlignment.spaceEvenly agar jarak dan ruang kosong di sekitar ketiganya terbagi rata.

Aksi: Buat ActionButtonsWidget dengan Row spaceEvenly
SS VS Code class ActionButtonsWidget Row mainAxisAlignment spaceEvenly tiga tombol aksi
Gambar E.1a – Class ActionButtonsWidget dengan Row spaceEvenly memanggil _buildActionButton untuk Pemasukan, Pengeluaran, dan Transfer
Penjelasan Kode

Ketiga tombol dibuat lewat method pembantu _buildActionButton(IconData icon, String label, Color color) agar kode tidak berulang tiga kali dengan struktur yang sama — cukup mengganti ikon, label, dan warna saja untuk setiap tombolnya (hijau untuk Pemasukan, merah untuk Pengeluaran, biru untuk Transfer).

2Mendesain Tombol dengan Container (Padding, Margin, Warna)

Di dalam _buildActionButton, setiap ikon dibungkus Container yang diberi padding agar ikon tidak menempel tepi kotak, decoration: BoxDecoration(color: color.withOpacity(0.2), borderRadius: BorderRadius.circular(12)) untuk warna latar transparan dan sudut membulat, lalu Column menumpuk Container ikon tersebut dengan label teks di bawahnya.

Aksi: Susun Container (padding, decoration) di dalam _buildActionButton
SS VS Code method buildActionButton Container padding decoration BoxDecoration warna transparan
Gambar E.1b – Method _buildActionButton dengan Container ber-padding dan BoxDecoration warna transparan sesuai parameter color
Hasil: Tiga Tombol Aksi Tampil Sejajar
SS hasil running ActionButtonsWidget tiga tombol Pemasukan Pengeluaran Transfer sejajar
Gambar E.1c – Tiga tombol aksi (Pemasukan, Pengeluaran, Transfer) tampil sejajar horizontal dengan jarak merata
3Menyusun Riwayat Transaksi dengan Column + ListTile

Karena daftar transaksi harus mengurut ke bawah, RecentTransactionsWidget memakai Column untuk menumpuk judul "Transaksi Terakhir" di atas sebuah Card yang membungkus beberapa ListTile berturut-turut, masing-masing dipisahkan Divider tipis.

Aksi: Buat RecentTransactionsWidget dengan Column, Card, dan Beberapa ListTile
SS VS Code class RecentTransactionsWidget Column Card ListTile leading title trailing
Gambar E.1d – Class RecentTransactionsWidget dengan Column membungkus Card berisi tiga ListTile (Makan Siang, Gaji Bulanan, Isi Bensin)
Penjelasan Kode

Setiap ListTile memakai leading: CircleAvatar(child: Icon(...)) untuk ikon kategori transaksi di sisi kiri, title: Text(...) untuk nama transaksi, subtitle: Text(...) untuk tanggal, dan trailing: Text(...) untuk nominal — persis mengikuti tiga slot leading/title/trailing yang dijelaskan pada dasar teori.

Hasil: Daftar Tiga Transaksi Tampil Rapi dalam Card
SS hasil running RecentTransactionsWidget daftar tiga transaksi Makan Siang Gaji Bulanan Isi Bensin
Gambar E.1e – Daftar "Transaksi Terakhir" menampilkan tiga ListTile: Makan Siang (−Rp 50.000), Gaji Bulanan (+Rp 5.000.000), dan Isi Bensin (−Rp 150.000)
4Mengintegrasikan Dashboard dengan SingleChildScrollView

Langkah terakhir menggabungkan seluruh komponen dari Modul 1 (GreetingWidget, BalanceCardWidget) dan Modul 2 (ActionButtonsWidget, RecentTransactionsWidget) ke dalam satu Column, lalu membungkus body Scaffold dengan SingleChildScrollView agar seluruh dashboard dapat di-scroll vertikal dan tidak overflow ketika daftar transaksi bertambah panjang.

Aksi: Bungkus body Scaffold dengan SingleChildScrollView
SS VS Code body Scaffold dibungkus SingleChildScrollView Padding Column empat widget dashboard
Gambar E.1f – Body Scaffold dibungkus SingleChildScrollView, Padding, dan Column berisi GreetingWidget, BalanceCardWidget, ActionButtonsWidget, dan RecentTransactionsWidget
Hasil: Dashboard Lengkap dan Dapat Di-scroll
SS hasil running dashboard lengkap Modul 1 dan Modul 2 dapat discroll tanpa overflow
Gambar E.1g – Dashboard lengkap menampilkan sapaan, kartu saldo, tombol aksi, dan riwayat transaksi tanpa error overflow
Dashboard berhasil menggabungkan empat widget dari dua modul sekaligus, dan SingleChildScrollView terbukti mencegah overflow ketika konten pada layar melebihi tinggi viewport.
E.2 Tugas Praktikum 2
Tugas 1 & 2 — Modul 2

Tugas 1 (Styling): pada widget Daftar Transaksi (ListTile), ubah warna trailing text pengeluaran menjadi merah dan text pemasukan menjadi hijau. Tugas 2 (Tambah Data): tambahkan 2 transaksi fiktif baru ke dalam daftar "Transaksi Terakhir" di bawah kode yang sudah ada.

1Tugas 1: Styling Warna Trailing Berdasarkan Jenis Transaksi

Alih-alih menulis warna merah/hijau secara manual pada setiap ListTile, dibuat method pembantu _buildTransactionTile({..., required bool isIncome}) yang menentukan warna dan tanda trailing secara otomatis: isIncome == true menghasilkan warna Colors.green dengan tanda "+", sedangkan isIncome == false menghasilkan warna Colors.red dengan tanda "−". Pendekatan ini membuat styling konsisten di seluruh item tanpa risiko lupa mengganti warna satu per satu.

Aksi: Buat Helper _buildTransactionTile dengan Parameter isIncome
SS VS Code method buildTransactionTile parameter isIncome menentukan warna trailing merah hijau
Gambar E.2a – Method _buildTransactionTile menentukan trailingColor dan prefix ("+"/"−") berdasarkan parameter isIncome
Penjelasan Kode

Sebelum: setiap ListTile ditulis manual dan berulang, dengan warna trailing di-hardcode langsung per item, misalnya trailing: Text('- Rp 50.000', style: TextStyle(color: Colors.red, ...)) pada item pengeluaran dan trailing: Text('+ Rp 5.000.000', style: TextStyle(color: Colors.green, ...)) pada item pemasukan — sehingga bila lupa mengganti warna, item baru bisa salah warna.

Sesudah: seluruh ListTile diganti menjadi pemanggilan satu method _buildTransactionTile({..., required bool isIncome}). Di dalamnya:

  • final Color trailingColor = isIncome ? Colors.green : Colors.red; — warna ditentukan otomatis dari parameter isIncome, bukan ditulis manual lagi.
  • final String prefix = isIncome ? '+ ' : '- '; — tanda "+"/"−" juga mengikuti jenis transaksi secara otomatis.
  • trailing: Text('$prefix$amount', style: TextStyle(color: trailingColor, ...)) — trailing text kini dibangun dari dua variabel di atas, sehingga warna dijamin selalu konsisten dengan jenis transaksinya.
Hasil: Warna Trailing Konsisten (Merah untuk Pengeluaran, Hijau untuk Pemasukan)
SS hasil running Tugas 1 Modul 2 warna trailing merah pengeluaran hijau pemasukan pada ListTile
Gambar E.2b – Setiap ListTile tetap menampilkan trailing merah untuk pengeluaran dan hijau untuk pemasukan, kini dihasilkan otomatis lewat helper alih-alih ditulis manual per item
2Tugas 2: Menambahkan 2 Transaksi Fiktif Baru

Dua pemanggilan _buildTransactionTile(...) baru ditambahkan di bawah tiga transaksi lama, masing-masing dipisahkan Divider: "Belanja Bulanan" senilai Rp 320.000 sebagai transaksi pengeluaran (isIncome: false), dan "Bonus Proyek" senilai Rp 750.000 sebagai transaksi pemasukan (isIncome: true).

Aksi: Tambahkan Dua Pemanggilan _buildTransactionTile Baru
SS VS Code dua pemanggilan buildTransactionTile baru Belanja Bulanan dan Bonus Proyek
Gambar E.2c – Dua transaksi baru, "Belanja Bulanan" (−Rp 320.000) dan "Bonus Proyek" (+Rp 750.000), ditambahkan di bawah daftar transaksi lama
Penjelasan Kode

Sebelum: Column di dalam Card hanya berisi tiga pemanggilan _buildTransactionTile(...) yang dipisahkan dua Divider — Makan Siang, Gaji Bulanan, dan Isi Bensin.

Sesudah: ditambahkan satu Divider(height: 1) lagi, diikuti dua pemanggilan _buildTransactionTile(...) baru di urutan paling bawah:

  • _buildTransactionTile(icon: Icons.shopping_cart, iconColor: Colors.orange, title: 'Belanja Bulanan', date: '08 Sep 2026', amount: 'Rp 320.000', isIncome: false) — transaksi pengeluaran baru, trailing otomatis berwarna merah lewat helper dari Tugas 1.
  • _buildTransactionTile(icon: Icons.card_giftcard, iconColor: Colors.purple, title: 'Bonus Proyek', date: '05 Sep 2026', amount: 'Rp 750.000', isIncome: true) — transaksi pemasukan baru, trailing otomatis berwarna hijau.

Karena kedua item baru ini memakai helper _buildTransactionTile yang sama, tidak diperlukan penulisan ListTile manual maupun pengaturan warna trailing tambahan — cukup mengisi parameter isIncome yang sesuai.

Hasil: Daftar Transaksi Bertambah Menjadi Lima Item
SS hasil running Tugas 2 Modul 2 daftar lima transaksi lengkap termasuk Belanja Bulanan dan Bonus Proyek
Gambar E.2d – Daftar "Transaksi Terakhir" bertambah dari tiga menjadi lima item, dengan "Belanja Bulanan" dan "Bonus Proyek" tampil di bagian bawah sebagai transaksi baru
Kedua tugas Modul 2 berjalan sesuai ekspektasi: warna trailing konsisten mengikuti jenis transaksi, dan dua transaksi baru berhasil tampil tanpa mengubah struktur ListTile yang sudah ada sebelumnya.

Melalui dua modul pada pertemuan ini, dashboard "Expense Tracker" berhasil dibangun secara bertahap: dimulai dari pengenalan StatelessWidget dan StatefulWidget pada Modul 1, hingga penerapan layouting yang lebih kompleks dengan Row, Column, Container, dan ListTile pada Modul 2.

Pada Modul 1, perbedaan paling mencolok antara GreetingWidget (Stateless) dan BalanceCardWidget (Stateful) terlihat jelas dari pengujian toggle visibilitas saldo: menekan ikon mata langsung mengubah teks nominal dari "Rp 5.000.000" menjadi "Rp *********" beserta perubahan ikon dari Icons.visibility menjadi Icons.visibility_off, membuktikan bahwa setState() benar-benar memicu rebuild pada widget terkait. Kedua tugas Modul 1 — pergantian warna tema ke teal dan penambahan teks nomor rekening — juga berhasil diterapkan tanpa mengganggu fungsi toggle tersebut.

Pada Modul 2, penggunaan Row dengan mainAxisAlignment.spaceEvenly terbukti efektif menyusun tiga tombol aksi dengan jarak yang seimbang, sementara kombinasi Column dan ListTile berhasil menampilkan daftar transaksi secara rapi lewat tiga slot leading/title/trailing. Pembungkusan seluruh dashboard dengan SingleChildScrollView juga terbukti mencegah overflow ketika daftar transaksi bertambah panjang pada Tugas 2, di mana dua transaksi fiktif baru berhasil ditambahkan tanpa masalah tampilan, dan warna trailing (merah/hijau) tetap konsisten berkat helper method _buildTransactionTile yang dibuat pada Tugas 1.

Berdasarkan seluruh tahapan praktikum yang telah dilaksanakan, diperoleh beberapa poin kesimpulan penting:

  1. StatelessWidget cocok untuk tampilan yang tidak pernah berubah seperti GreetingWidget, sedangkan StatefulWidget wajib dipakai ketika tampilan perlu merespons interaksi pengguna, seperti toggle visibilitas saldo pada BalanceCardWidget.
  2. setState() adalah mekanisme inti yang menghubungkan perubahan data pada state dengan pembaruan tampilan (rebuild) di layar; tanpa memanggilnya, perubahan variabel tidak akan pernah terlihat oleh pengguna.
  3. Row dan Column adalah pasangan widget layouting dasar yang saling melengkapi — Row untuk susunan horizontal seperti deretan tombol aksi, Column untuk susunan vertikal seperti daftar transaksi yang terus bertambah ke bawah.
  4. ListTile mempercepat pembuatan baris daftar yang konsisten lewat tiga slot leading/title/trailing, dibanding menyusun Row/Column manual untuk setiap barisnya.
  5. Membungkus konten dengan SingleChildScrollView adalah praktik penting pada dashboard yang kontennya dapat bertambah panjang, agar aplikasi tidak mengalami error overflow ketika data bertambah.
  6. Memisahkan logika berulang ke dalam method pembantu (seperti _buildActionButton dan _buildTransactionTile) terbukti membuat kode lebih ringkas, konsisten, dan mudah dikembangkan — terlihat jelas ketika menambahkan dua transaksi baru pada Tugas 2 hanya membutuhkan dua pemanggilan method tanpa menulis ulang struktur ListTile dari awal.

Seluruh source code praktikum ini (Modul 1 dan Modul 2, beserta hasil tugas keduanya) dapat diakses pada branch pertemuan2 repository Github berikut: