Belajar Flutter - Widgets Dasar & Layout
Episode 4 of 23

Belajar Flutter - Widgets Dasar & Layout

Episode ini membangun fondasi tampilan Flutter: perbedaan StatelessWidget dan StatefulWidget, layout dasar dengan Row, Column, Stack, dan Container, pengaturan spacing, alignment, dan constraints, serta widget composition dan builder patterns untuk membangun UI yang reusable.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Project pertama kalian sudah berjalan di episode 3. Sekarang waktunya memahami bahan dasar pembentuk UI Flutter: widget. Hampir semua hal di Flutter adalah widget — teks, tombol, jarak, bahkan layout itu sendiri. Episode 4 membedah empat hal mendasar: kapan memakai StatelessWidget dan StatefulWidget, layout dasar dengan Row, Column, Stack, dan Container, cara mengatur spacing, alignment, dan constraints, serta widget composition dan builder patterns untuk membangun UI yang bersih dan reusable.

StatelessWidget vs StatefulWidget

Widget Tanpa State vs Widget Berstate

Flutter membagi widget menjadi dua keluarga:

  • StatelessWidget: widget yang tampilannya tidak berubah setelah di-build. Cocok untuk teks statis, ikon, dan tampilan yang bergantung penuh pada parameter.
  • StatefulWidget: widget yang menyimpan state yang bisa berubah, memicu build ulang saat state berubah.
Perbandingan dua jenis widget
class JudulStatis extends StatelessWidget {
  const JudulStatis({super.key});
 
  @override
  Widget build(BuildContext context) {
    return const Text('Ini tidak berubah');
  }
}
 
class TombolBerubah extends StatefulWidget {
  const TombolBerubah({super.key});
 
  @override
  State<TombolBerubah> createState() => _TombolBerubahState();
}
 
class _TombolBerubahState extends State<TombolBerubah> {
  bool _ditekan = false;
 
  @override
  Widget build(BuildContext context) {
    return Text(_ditekan ? 'Ditekan' : 'Belum');
  }
}

Aturan praktis: mulai dengan StatelessWidget. Ubah ke StatefulWidget hanya ketika ada data yang harus berubah dan memicu build ulang — keputusan yang menekan biaya rebuild sejak awal.

Layout Dasar: Row, Column, Stack, dan Container

Row dan Column

Dua widget layout paling sering dipakai:

  • Row: menata children secara horizontal.
  • Column: menata children secara vertikal.
Column dengan dua anak
Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    Text('Baris pertama'),
    SizedBox(height: 8),
    Text('Baris kedua'),
  ],
)

SizedBox(height: 8) menyisipkan jarak vertikal antar teks. crossAxisAlignment: CrossAxisAlignment.start menyejajarkan children ke kiri pada sumbu silang.

Stack dan Container

  • Stack: menumpuk children di atas satu sama lain, berguna untuk overlay.
  • Container: widget serbaguna yang menggabungkan padding, margin, warna, dan ukuran.
Stack dengan overlay dan Container
Stack(
  children: [
    Container(
      width: 200,
      height: 200,
      color: Colors.blue,
    ),
    Positioned(
      left: 16,
      top: 16,
      child: Container(
        padding: EdgeInsets.all(8),
        color: Colors.white,
        child: const Text('Badge'),
      ),
    ),
  ],
)

Positioned menempatkan child pada posisi relatif terhadap Stack. EdgeInsets.all(8) menambahkan padding seragam di dalam Container, dan kombinasi keduanya adalah pola umum untuk badge overlay.

Spacing, Alignment, dan Constraints

Spacing dengan SizedBox dan Spacer

Di dalam Row atau Column, SizedBox memberi jarak tetap, sedangkan Spacer menyerap sisa ruang:

Menyebar elemen dengan Spacer
Row(
  children: [
    const Text('Kiri'),
    Spacer(),
    const Text('Kanan'),
  ],
)

Spacer tanpa parameter memakai flex default sehingga mendorong Text('Kanan') ke ujung kanan. Ini pola cepat untuk menyusun baris dua sisi.

Alignment dan Constraints

Setiap widget menerima constraints dari parent dan memberi ukuran hasil ke parent. Memahami alur ini membantu men-debug layout aneh:

  • mainAxisAlignment — posisi children di sepanjang sumbu utama.
  • crossAxisAlignment — posisi children di sepanjang sumbu silang.
  • Constraint yang terlalu ketat menyebabkan error overflow, yang ditampilkan sebagai garis kuning-hitam saat debug.

MainAxisAlignment.spaceEvenly membagi ruang kosong secara merata di antara dan di sekitar children, sedangkan spaceBetween memusatkan pembagian di tengah sehingga ujung-ujungnya menempel ke tepi.

Widget Composition dan Builder Patterns

Composition over Inheritance

Flutter mendorong komposisi: bangun widget kompleks dari widget sederhana, bukan menurunkan subclass. Kebiasaan yang harus ditanam sejak awal adalah memecah build besar menjadi widget-widget kecil yang reusable, seperti contoh berikut:

Widget komposisi sederhana
class AvatarCard extends StatelessWidget {
  const AvatarCard({super.key, required this.nama});
 
  final String nama;
 
  @override
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        leading: const CircleAvatar(child: Icon(Icons.person)),
        title: Text(nama),
      ),
    );
  }
}

AvatarCard mengemas Card, ListTile, dan CircleAvatar menjadi satu widget bernama. Parameter required this.nama membuat widget ini terasa seperti API yang jelas — pola yang akan kalian pakai terus sepanjang series.

Builder Patterns

Beberapa widget memakai builder function alih-alih children tetap, misalnya ListView.builder untuk daftar panjang:

Listview builder untuk daftar dinamis
ListView.builder(
  itemCount: 100,
  itemBuilder: (context, index) {
    return ListTile(title: Text('Item $index'));
  },
)

ListView.builder hanya membangun item yang terlihat di layar — efisien untuk daftar ratusan atau ribuan entri, dan menjadi dasar yang akan kita pakai saat membangun aplikasi nyata.

Penutup

Inti yang harus dibawa pulang:

  • StatelessWidget untuk tampilan statis; StatefulWidget untuk tampilan yang berubah.
  • Row menata horizontal, Column vertikal, Stack menumpuk, Container serbaguna.
  • SizedBox memberi jarak tetap; Spacer menyerap ruang sisa.
  • Pahami constraints: setiap widget menerima batasan dari parent dan mengembalikan ukuran.
  • Bangun UI lewat komposisi widget kecil yang reusable, bukan inheritance.
  • ListView.builder mem-build item secara lazy untuk daftar panjang.

Di episode 5 selanjutnya kita membahas input, forms, dan interaction — handling user input dengan TextField, buttons, dan gestures, form validation dan controllers, navigation dan routing sederhana, serta penggunaan SnackBar, dialogs, dan modal bottom sheets. Kalian mulai membuat aplikasi yang benar-benar interaktif.

Belajar Flutter - Widgets Dasar & Layout | Belajar Flutter