Seluruh tampilan pada aplikasi Flutter tersusun atas satu jenis bahan yang sama, yaitu widget. Topik ini membangun mental model komposisi (composition), yaitu cara memandang antarmuka sebagai pohon widget yang saling bersarang, menjelaskan alasan widget diperlakukan sebagai konfigurasi tak berubah, dan melatih pembacaan kode Flutter sebagai pohon. Setelah topik ini selesai dibaca, struktur kode tampilan Flutter dapat diikuti dari akar hingga daun.
Widget sebagai satuan pembangun antarmuka#
Widget adalah deskripsi atas sebagian antarmuka pengguna (user interface, UI), mulai dari layar utuh hingga potongan kecil seperti teks, ikon, dan jarak kosong. Deskripsi itu memuat konfigurasi widget tersebut, misalnya teks apa yang ditampilkan dan warna apa yang digunakan. Hampir semua hal pada Flutter berbentuk widget, termasuk hal yang pada framework lain dianggap properti, seperti jarak dan perataan.
Cara Flutter menyusun layar adalah komposisi: widget berada di dalam widget yang lebih besar, dan pola itu berulang hingga tingkat terdalam. Tombol berisi teks, halaman berisi tombol, dan aplikasi berisi halaman. Tidak ada mekanisme khusus untuk menggabungkan semuanya, karena penyusunannya selalu mengikuti pola yang sama.
Pergeseran dari atribut ke widget paling terasa pada jarak. Untuk memberi jarak di sekeliling tombol, Flutter tidak menyediakan properti padding pada tombol, melainkan widget Padding yang membungkus tombol tersebut. Semua bagian tampilan bersandar pada satu model yang sama, sehingga tidak ada pengecualian yang perlu dihafal.
Widget yang disebut hingga titik ini semuanya bawaan Flutter. Library material.dart menyediakan ratusan widget yang dikelompokkan dalam katalog resmi, mulai dari widget penataan, widget tampilan, hingga widget navigasi. Widget buatan sendiri, seperti KartuProfilApp pada topik ini, tersusun dari widget bawaan yang sama tanpa mekanisme tambahan.
Widget sebagai konfigurasi tak berubah#
Widget bersifat immutable, yaitu tidak dapat diubah setelah dibuat, sehingga seluruh datanya ditetapkan saat konstruksi dan tetap sama selama widget itu hidup. Apabila tampilan harus berubah, Flutter tidak memodifikasi widget lama, melainkan membuat widget baru dengan konfigurasi yang diinginkan. Siklus pembuatan ulang ini disebut rebuild dan berlangsung sangat sering selama aplikasi berjalan.
Widget yang sering dibuat dan dibuang itu sengaja dirancang murah. Widget hanyalah objek konfigurasi yang ringan, sehingga membuatnya tidak berarti menggambar ulang piksel apa pun. Beban yang sesungguhnya, yaitu penghitungan ukuran dan penggambaran, berada pada lapisan lain yang bertahan lebih lama.
Di balik layar, Flutter memelihara dua lapisan pendukung: Element yang menyimpan posisi setiap widget pada pohon beserta daur hidupnya, dan RenderObject yang menghitung ukuran, menetapkan posisi, dan menggambar. Widget boleh berganti setiap saat, sedangkan kedua lapisan itu hanya diperbarui apabila konfigurasinya benar-benar berubah. Pada tahap ini, kesadaran atas keberadaan keduanya sudah cukup, karena pemisahan antara widget dan kedua lapisan itulah yang membuat rebuild menjadi murah.
Membaca layar sebagai pohon widget#
Karena setiap widget dapat berisi widget lain, satu layar utuh berbentuk pohon (tree) dengan widget aplikasi sebagai akar dan widget terkecil sebagai daun. Diagram berikut menggambarkan pohon widget untuk kartu profil sederhana yang menampilkan nama dan status.
Pohon yang sama dapat ditulis sebagai satu berkas Dart utuh. Kode berikut adalah aplikasi lengkap yang menghasilkan pohon pada diagram. Nama widget pada kode berpadanan langsung dengan kotak pada diagram, dan tingkat indentasi berpadanan dengan kedalaman pohon.
// tidak-dijalankan
import 'package:flutter/material.dart';
void main() {
runApp(const KartuProfilApp());
}
/// Aplikasi kartu profil sederhana.
class KartuProfilApp extends StatelessWidget {
const KartuProfilApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Kartu Profil')),
body: const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Citra', style: TextStyle(fontSize: 24)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.school),
Text('Mahasiswa Informatika'),
],
),
],
),
),
);
}
}Pembacaannya dimulai dari akar: runApp memasang KartuProfilApp sebagai widget akar aplikasi. MaterialApp menyediakan kerangka aplikasi seperti tema dan navigasi dasar, kemudian Scaffold menyediakan kerangka satu layar dengan slot appBar dan body. AppBar menampilkan judul, sedangkan body diisi Column yang menata dua anak secara vertikal, yaitu Text nama dan Row yang berisi Icon serta Text status. Setiap butir pada daftar children adalah satu cabang pohon.
Gaya penulisan bersarang seperti itu memang membuat kode menjorok dalam, dan itulah wujud nyata dari model komposisi. Editor dengan dukungan format otomatis merapikan indentasi tersebut, sehingga kedalaman pohon tetap terbaca. Keterampilan yang perlu dibangun adalah membaca kode dari luar ke dalam, sama seperti membaca diagram dari akar ke daun.
Kesalahan umum#
- Menulis satu widget raksasa untuk satu layar. Widget sepanjang ratusan baris sulit dibaca dan sulit diuji. Penyebab yang sering muncul adalah anggapan bahwa memecah widget menambah biaya, padahal widget ringan untuk dibuat. Perbaikannya, pecah layar menjadi widget kecil yang diberi nama sesuai perannya.
- Mencari properti jarak pada setiap widget. Tidak semua widget memiliki properti
paddingataumargin, sehingga pencarian semacam itu tidak menemukan apa pun. Perbaikannya, bungkus widget denganPadding, atau gunakanContainerapabila sekaligus perlu dekorasi.
Ringkasan#
- Seluruh UI Flutter adalah pohon widget yang tersusun lewat komposisi, mulai dari
MaterialApphinggaText. - Widget bersifat immutable, sehingga perubahan tampilan selalu berarti membuat widget baru, bukan mengubah widget lama.
- Widget adalah konfigurasi yang murah untuk dibuat, sedangkan
ElementdanRenderObjectadalah lapisan yang bertahan dan menangani penggambaran. - Membaca kode Flutter sama dengan membaca pohon: tingkat indentasi menunjukkan kedalaman bersarang.
Referensi#
- Building user interfaces with Flutter — Flutter — Panduan resmi membangun UI Flutter, termasuk pengantar model widgetnya.
- Widget catalog — Flutter — Katalog widget bawaan yang dikelompokkan menurut kegunaannya.