Back to IF3210 Pengembangan Aplikasi Piranti Bergerak
Flutter Widgets and App Architecture
Questions/Cues
- Apa perbedaan utama
StatelessWidgetdanStatefulWidget, dan kapan menggunakan masing-masing?- Mengapa Flutter menggunakan composition over inheritance untuk membangun UI?
- Apa itu state lifting dan mengapa diperlukan dalam arsitektur Flutter?
- Bagaimana switch expression, spread, dan
if/fordalam collection literal menyederhanakan kode?- Apa peran Flutter Inspector dalam proses debugging UI?
Reference Points
- IF3210 Pengembangan Aplikasi Piranti Bergerak (Slides 13a: 30-32, 13b: 24-39)
Struktur Proyek Flutter dan Entry Point
Proyek Flutter memiliki struktur direktori yang terorganisir: folder
lib/berisi seluruh kode Dart, denganlib/main.dartsebagai entry point aplikasi. Fungsimain()memanggilrunApp()yang menerima widget root. Widget root biasanya adalahMaterialAppyang menyediakan tema Material Design, routing, dan konfigurasi aplikasi secara global.Setiap widget mendefinisikan UI-nya melalui method
build()yang mengembalikan widget tree. Method ini dipanggil oleh framework Flutter setiap kali widget perlu dirender ulang. Prinsip utamanya: UI adalah fungsi dari state — tampilan ditentukan sepenuhnya oleh data, bukan oleh mutasi langsung elemen DOM seperti di web tradisional.StatelessWidget vs StatefulWidget
Flutter membagi widget menjadi dua kategori berdasarkan kemampuan mengelola state:
flowchart TD A["Widget baru dibutuhkan"] --> B{"Apakah UI perlu</br>berubah berdasarkan</br>data internal?"} B -->|"Tidak"| C["StatelessWidget"] B -->|"Ya"| D["StatefulWidget"] C --> E["build() dipanggil</br>hanya saat parent</br>membangun ulang"] D --> F["State object</br>terpisah dari Widget"] F --> G["setState() memicu</br>build() ulang"] C --> H["Contoh: ikon,</br>label, kartu statis"] D --> I["Contoh: form,</br>animasi, counter"]
StatelessWidgettidak memiliki state internal yang berubah — sekali dibuat, tampilan hanya bergantung pada properti yang diteruskan dari parent. Methodbuild()hanya dipanggil ulang jika parent membangun ulang.
StatefulWidgetterdiri dari dua objek: widget itu sendiri (immutable) dan objekStateterpisah yang dapat berubah. MemanggilsetState()memberitahu framework bahwa state telah berubah danbuild()perlu dipanggil ulang untuk merefleksikan perubahan tersebut di UI.Control Flow Lanjutan: switch Expression, Spread, if, dan for
Dart 3 memperkenalkan switch expression (berbeda dari switch statement): ekspresi ini dievaluasi menjadi nilai dan dapat digunakan langsung di dalam ekspresi lain. Sintaksnya menggunakan
=>dan tidak memerlukanbreak. Kompiler memastikan semua kemungkinan nilai tertangani (exhaustive).Di dalam collection literals (
[],{},{:}), Dart mendukung tiga operator khusus yang sangat berguna untuk membangun UI Flutter secara deklaratif:
- Spread operator
...: menyisipkan seluruh elemen koleksi lain ke dalam koleksi saat ini. Juga tersedia...?untuk spread yang null-safe.ifdalam collection: menyertakan elemen secara kondisional tanpa perlu membuat list sementara. Contoh:[Widget1(), if (kondisi) Widget2()].fordalam collection: menghasilkan elemen secara iteratif. Contoh:[for (var item in items) ItemWidget(item)].Ketiga fitur ini menjadi tulang punggung cara Flutter membangun widget tree secara dinamis dan deklaratif di dalam method
build().Konvensi Kode Dart
Tim Dart mendefinisikan konvensi penamaan yang konsisten:
Konteks Konvensi Contoh Variabel & fungsi lowerCamelCaseuserName,fetchData()Class & enum UpperCamelCaseUserProfile,AppStatusPackage & file snake_caseuser_profile.dart,my_appParameter tidak dipakai _(_, index) => ...Konstanta global Awalan kkDefaultPaddingString literal Single quote '...''Halo'Dokumentasi menggunakan
///(doc comment) untuk komentar yang muncul di hover tooltip IDE, dan/** */untuk komentar blok multi-baris.Data Models: PODO (Plain Old Dart Objects)
Model data di Dart biasanya diimplementasikan sebagai PODO (Plain Old Dart Objects) — class sederhana yang berisi data dengan getter dan setter. Konvensi Flutter merekomendasikan field privat dengan
_prefix dan akses via getter/setter publik untuk enkapsulasi yang baik. MethodcopyWith(),toString(),==, danhashCodesering ditambahkan untuk kemudahan penggunaan (value semantics).State Lifting: Arsitektur State Antar Widget
Ketika dua atau lebih widget perlu berbagi atau saling mempengaruhi state yang sama, solusinya adalah state lifting: pindahkan state ke widget leluhur terdekat yang menjadi parent bersama kedua widget tersebut.
Widget parent meneruskan data ke child via constructor parameters (props). Untuk memungkinkan child mengubah state di parent, parent meneruskan callback function sebagai parameter — ini adalah closure yang menangkap referensi ke
setState()dari parent. Ketika child memanggil callback tersebut, state di parent berubah dan seluruh subtree dirender ulang.Alur state lifting secara sederhana:
- State disimpan di widget parent (misal
_selectedIndex)- Data diteruskan ke bawah ke child yang membutuhkan tampilan (
child1.selectedIndex = _selectedIndex)- Callback diteruskan ke child yang perlu memicu perubahan (
child2.onSelected = (i) => setState(() => _selectedIndex = i))Styling dan List di Flutter
Flutter mendukung Google Fonts melalui package
google_fontsyang mengunduh dan men-cache font dari Google Fonts API. Rounded corners dibuat menggunakanBorderRadius.circular()pada dekorasi widget.Untuk efek transparansi gambar, terdapat dua pendekatan utama:
- Widget
Opacity: Menerapkan transparansi pada seluruh subtree di bawahnya. Subtree dirender ke offscreen buffer terlebih dahulu sebelum transformasi diterapkan, yang lebih berat secara performa.- Properti
colorpadaImage: Menerapkan warna sebagai tint (biasanya digabung dengancolorBlendMode). Ini merupakan bagian dari proses rendering gambar standar dan dapat diakselerasi oleh GPU.Untuk filter data pada list, gunakan method
.where()dariIterableyang menerima fungsi predikat dan mengembalikanIterablebaru berisi elemen yang memenuhi kondisi. Kombinasikan dengan.toList()untuk mengkonversi hasilnya.Dalam Flutter, widget yang melebihi batas layar (overflow) tidak otomatis terbungkus atau dapat discroll. Pengembang harus menyediakan widget pendukung secara eksplisit:
SingleChildScrollView: membungkus satu child yang mungkin lebih besar dari layar — cocok untuk form atau konten panjang yang tidak diketahui jumlahnya.Expanded: mengisi ruang yang tersedia dalamRowatauColumn— penting agarListViewdi dalamColumnbisa scrollable tanpa overflow.Flutter Inspector
Flutter Inspector adalah tool developer yang terintegrasi di Android Studio dan VS Code. Fungsinya meliputi visualisasi widget tree secara interaktif, pemeriksaan properti setiap widget, highlight batas widget di layar, dan debug masalah layout seperti overflow. Inspector membantu memahami bagaimana widget tree yang kompleks disusun dan di mana masalah rendering terjadi.
Flutter membangun UI secara deklaratif menggunakan widget tree dengan
build()sebagai fungsi dari state.StatelessWidgetdigunakan untuk UI statis;StatefulWidgetuntuk UI yang berubah, dengansetState()memicu rebuild. Composition over inheritance adalah prinsip utama — widget dibuat dengan menggabungkan widget yang lebih kecil, bukan mewarisi. State lifting memindahkan state ke parent bersama dan meneruskan callback closure ke bawah untuk mutasi. Collection literal mendukung spread...,if, danforuntuk membangun widget tree dinamis secara deklaratif. Model data diimplementasikan sebagai PODO, scrolling dikelola viaSingleChildScrollView/Expanded, dan Flutter Inspector adalah alat debugging layout utama.
Additional Information
InheritedWidget dan Provider
State lifting manual efektif untuk hierarki widget yang dangkal, tetapi menjadi tidak praktis untuk aplikasi besar.
InheritedWidgetadalah mekanisme Flutter untuk meneruskan data ke bawah widget tree tanpa harus mengoper lewat setiap level. Package Provider (dan penggantinya Riverpod) membangun abstraksi di atasInheritedWidgetuntuk state management yang lebih scalable.Widget Keys
Keydi Flutter membantu framework mengidentifikasi widget secara unik saat widget tree direkonstruksi. Tanpa key, Flutter bisa gagal mempertahankan state yang tepat ketika urutan widget berubah (misalnya saat item list di-reorder).ValueKey,ObjectKey, danUniqueKeyadalah varian yang tersedia.const Widget untuk Performa
Menandai widget dengan
const(saat semua propertinya adalah konstanta compile-time) membuat Flutter melewati proses rekonstruksi widget tersebut selama rebuild. Ini adalah optimasi performa yang signifikan terutama untuk widget yang sering dirender ulang karena adanya parentStatefulWidget.Proyek Eksplorasi Mandiri
- Buat aplikasi Flutter sederhana dengan counter yang diimplementasikan menggunakan
StatefulWidget, kemudian refaktor menggunakan state lifting dengan dua widget child yang berbeda- Implementasikan daftar item yang dapat difilter menggunakan
.where()— hubungkan filter input (TextField) dengan list output menggunakan state lifting- Eksplorasi Flutter Inspector di Android Studio: buka widget tree, inspeksi properti padding/margin, dan identifikasi widget mana yang merupakan
StatefulWidgetBacaan Lanjutan
- Dokumentasi Resmi Flutter: “Introduction to widgets” (docs.flutter.dev/ui/widgets-intro)
- Dokumentasi Resmi Flutter: “State management” (docs.flutter.dev/data-and-backend/state-mgmt)
- Codelab: “Your first Flutter app” (docs.flutter.dev/get-started/codelab)
- “Flutter in Action” (Eric Windmill) — Bab arsitektur widget dan state management