Belajar Flutter dari Awal: Membangun Layout Sederhana dengan Widget (Part 3)
Rifqi An
Membangun Layout Sederhana dengan Widget (Part 3): Merangkai Pikiran Jadi Tampilan Indah!
Halo gaes! Balik lagi sama kita di seri tutorial belajar Flutter dari awal! Gimana ngodingnya, aman? Atau masih sering kena bug misterius yang bikin pengen banting keyboard? Tenang, itu normal kok! Namanya juga programmer, hidup itu penuh tantangan kayak mencari jarum di tumpukan kode orang lain. ðŸ«
Di part sebelumnya kita udah kenalan sama widget-widget dasar buat ngebangun layout lurus-lurus aja kayak `Row` dan `Column`. Nah, sekarang kita mau naik level dikit nih! Kita bakal ngulik beberapa widget penyelamat yang bikin layout kita jadi lebih fleksibel, rapi, dan pastinya… cakep! Siap-siap ngopi, karena sesi ngoding kita kali ini bakal sedikit lebih seru!
Daftar Isi
- Pendahuluan: Sekilas Ingat yang Lalu
- Container dan Padding: Teman Setia Ngoding
- Expanded dan Flexible: Biar Layout Gak Kaku
- Ngoprek Bareng: Contoh Layout Kartu Produk
- Sedikit Ngintip Stack: Susun-susun Widget
- Latihan: Penyelamat Deadline!
Pendahuluan: Sekilas Ingat yang Lalu
Sebelum kita loncat ke materi baru, yuk kita inget-inget lagi pelajaran sebelumnya. Intinya, Flutter itu semua serba widget. Mau teks, gambar, tombol, sampai layout-nya sendiri, semua adalah widget. Dan buat nyusun widget secara horizontal atau vertikal, kita pakai `Row` dan `Column`. Simpel kan?
Tapi kadang, kita butuh lebih dari sekadar susun lurus. Misalnya, kita pengen ada jarak antara elemen, ngasih warna latar, atau bikin satu elemen ngisi semua sisa ruang yang kosong. Nah, di sinilah widget-widget keren yang bakal kita bahas sekarang berperan!
Container dan Padding: Teman Setia Ngoding
Container: Kotak Serbaguna Idaman Programmer
Kalau di dunia web ada `div`, nah di Flutter kita punya `Container`. Ini adalah widget serbaguna banget! `Container` bisa kita pakai buat ngasih warna latar, ngasih padding, margin, ngatur lebar dan tinggi, sampai ngasih dekorasi lain kayak border atau shadow. Ibaratnya, `Container` ini adalah kardus ajaib yang bisa kita modifikasi sesuka hati buat membungkus widget lain.
Contohnya gini nih, kalau kita pengen teks punya latar belakang biru dan jarak dari pinggir:
// Kode di dalam build method kamu
Container(
color: Colors.blueAccent, // Kasih warna latar biru
padding: EdgeInsets.all(20.0), // Kasih padding 20 pixel di semua sisi
margin: EdgeInsets.symmetric(vertical: 10.0), // Kasih margin atas & bawah
child: Text(
'Halo, Dunia Flutter!',
style: TextStyle(color: Colors.white, fontSize: 18.0),
),
)
Gimana? Kelihatan langsung lebih rapi kan? Tinggal ganti-ganti propertinya, langsung jadi cakep!
Padding: Si Penyelamat Jarak
Meskipun `Container` udah bisa ngasih padding, kadang kita cuma butuh padding doang tanpa harus ngasih warna atau dekorasi lainnya. Nah, di sinilah widget `Padding` jagoannya. `Padding` cuma punya satu tugas: ngasih jarak antara dirinya dengan child widget-nya. Lebih spesifik dan efisien kalau memang cuma butuh padding.
Contohnya sama kayak di atas, tapi kita pakai `Padding` murni:
// Kode di dalam build method kamu
Padding(
padding: EdgeInsets.fromLTRB(10.0, 5.0, 10.0, 5.0), // padding kiri, atas, kanan, bawah
child: Text(
'Teks ini pakai Padding langsung!',
style: TextStyle(fontSize: 16.0),
),
)
Jadi, kalau cuma butuh jarak, pakai `Padding`. Kalau butuh jarak plus dekorasi lainnya, `Container` adalah pilihan terbaikmu!
Expanded dan Flexible: Biar Layout Gak Kaku
Ini dia duo maut yang bakal bikin layout kamu anti-kaku dan responsif! Pernah kan bikin `Row` atau `Column`, terus isinya gak pas di tengah atau ada satu elemen yang pengennya ngisi sisa ruang kosong? Nah, kenalan sama `Expanded` dan `Flexible`!
Expanded: Si Ambisius yang Ngisi Semua Ruang
`Expanded` ini gampangannya adalah widget yang bilang, "Pokoknya aku mau ngambil semua sisa ruang yang ada di `Row` atau `Column` ini!" Dia egois banget, gak mau berbagi kalau ada ruang kosong. Kalau ada beberapa `Expanded` di dalam satu `Row` atau `Column`, mereka akan berbagi ruang kosong itu secara merata.
Contohnya kita punya 3 kotak di dalam `Row`. Kotak tengah kita kasih `Expanded`:
// Kode di dalam build method kamu
Row(
children: <Widget>[
Container(
color: Colors.red,
width: 50.0,
height: 50.0,
),
Expanded( // Aku mau ngisi sisa ruang kosong!
child: Container(
color: Colors.green,
height: 50.0,
child: Center(
child: Text('Aku Expanded!'),
),
),
),
Container(
color: Colors.blue,
width: 50.0,
height: 50.0,
),
],
)
Hasilnya, `Container` merah dan biru ukurannya tetap 50x50, tapi `Container` hijau yang di-wrap `Expanded` akan melebar untuk mengisi semua ruang yang tersisa!
Flexible: Si Pengalah yang Mau Berbagi
`Flexible` ini saudaranya `Expanded`, tapi dia lebih santai. Dia bilang, "Aku sih mau ngambil sisa ruang, tapi kalau isiku udah cukup, aku gak perlu maksain diri buat lebar-lebar banget." Artinya, `Flexible` ini hanya akan mengambil ruang seperlunya, tapi juga bisa melebar jika ada ruang kosong dan child-nya butuh lebih. Property `flex` bisa dipakai untuk mengatur rasio pembagian ruangnya.
Kalau contoh di atas kita ganti `Expanded` jadi `Flexible`:
// Kode di dalam build method kamu
Row(
children: <Widget>[
Container(
color: Colors.red,
width: 50.0,
height: 50.0,
),
Flexible( // Aku santai aja, sesuai isi teksku
child: Container(
color: Colors.orange, // Ganti warna biar beda
height: 50.0,
child: Center(
child: Text('Aku Flexible, ukuranku sesuai isi'),
),
),
),
Container(
color: Colors.blue,
width: 50.0,
height: 50.0,
),
],
)
Dengan `Flexible`, `Container` oranye akan mengambil ruang hanya selebar teksnya, kecuali jika tidak ada cukup ruang, baru dia akan mengecil. Kalau kamu pengen dia ngisi ruang kayak `Expanded`, kamu bisa set `flexFit: FlexFit.tight` (yang mana ini adalah defaultnya `Expanded`).
Ngoprek Bareng: Contoh Layout Kartu Produk
Oke, biar gak cuma teori doang, yuk kita coba gabungkan semua yang udah kita pelajari buat bikin sebuah kartu produk sederhana. Anggap aja kamu lagi lembur bikin aplikasi toko online.
Kita bakal bikin kartu dengan gambar di kiri dan detail produk (nama, harga, deskripsi) di kanan. Kira-kira bakal pakai `Row`, `Column`, `Container`, `Padding`, dan `Expanded`.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Layout Ngopi',
home: Scaffold(
appBar: AppBar(
title: Text('Kartu Produk Ngopi Bareng'),
backgroundColor: Colors.brown[700],
),
body: Center(
child: ProductCard(), // Panggil widget ProductCard kita
),
),
);
}
}
class ProductCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(16.0), // Margin di luar kartu
padding: EdgeInsets.all(12.0), // Padding di dalam kartu
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0), // Sudut melengkung
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 7,
offset: Offset(0, 3), // Posisi shadow
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start, // Align item dari atas
children: <Widget>[
// Bagian kiri: Gambar Produk
Container(
width: 100.0,
height: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
image: DecorationImage(
image: NetworkImage('https://via.placeholder.com/150/FF8C00/FFFFFF?text=Kopi+Mantap'), // Gambar dummy
fit: BoxFit.cover,
),
),
),
SizedBox(width: 12.0), // Kasih jarak antar gambar dan detail
// Bagian kanan: Detail Produk
Expanded( // Ini penting! Biar detail produk mengisi sisa ruang
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // Align teks dari kiri
children: <Widget>[
Text(
'Kopi Robustasa Premium',
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
color: Colors.brown[900],
),
),
SizedBox(height: 4.0), // Jarak antar judul dan harga
Text(
'Rp 35.000',
style: TextStyle(
fontSize: 16.0,
color: Colors.green[700],
fontWeight: FontWeight.w600,
),
),
SizedBox(height: 8.0), // Jarak antar harga dan deskripsi
Text(
'Kopi pilihan dari pegunungan Sindoro. Aroma tajam, rasa pahit manis. Cocok buat teman ngoding sampai subuh.',
style: TextStyle(
fontSize: 12.0,
color: Colors.grey[700],
),
maxLines: 2, // Maksimal 2 baris
overflow: TextOverflow.ellipsis, // Kalau kepanjangan, pakai elipsis (...)
),
SizedBox(height: 8.0), // Jarak dari deskripsi ke tombol
Align( // Align tombol ke kanan bawah
alignment: Alignment.bottomRight,
child: ElevatedButton(
onPressed: () {
print('Tambah ke keranjang!');
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.brown, // Warna tombol
foregroundColor: Colors.white, // Warna teks tombol
),
child: Text('Beli Sekarang'),
),
),
],
),
),
],
),
);
}
}
Coba deh copas kode di atas dan jalanin di emulator atau HP kamu. Pasti langsung keliatan hasilnya! Kita pakai `Container` untuk membungkus kartu secara keseluruhan dengan padding, margin, border-radius, dan box-shadow. Lalu di dalamnya ada `Row` untuk meletakkan gambar dan detail produk secara horizontal. Bagian detail produk di-wrap dengan `Expanded` agar bisa mengisi sisa ruang setelah gambar. Di dalam `Expanded`, kita pakai `Column` untuk menyusun teks dan tombol secara vertikal.
Sedikit Ngintip Stack: Susun-susun Widget
Satu lagi widget layout yang gak kalah penting, tapi mungkin kita bahas lebih dalam di lain kesempatan, adalah `Stack`. Kalau `Row` nyusun widget dari kiri ke kanan dan `Column` dari atas ke bawah, nah `Stack` ini nyusun widget kayak tumpukan kartu. Dia bisa numpuk beberapa widget di atas satu sama lain.
Ini berguna banget buat bikin efek-efek kayak notifikasi di atas avatar, atau tulisan di atas gambar. Contoh paling gampangnya gini nih:
// Kode di dalam build method kamu
Stack(
children: <Widget>[
Container( // Background
width: 150.0,
height: 150.0,
color: Colors.blue[200],
),
Positioned( // Widget yang akan diletakkan di posisi spesifik
bottom: 10.0,
right: 10.0,
child: Container(
padding: EdgeInsets.all(5.0),
color: Colors.red,
child: Text(
'NEW!',
style: TextStyle(color: Colors.white, fontSize: 12.0),
),
),
),
],
)
Di situ, `Container` biru akan jadi latar belakang, lalu `Container` merah dengan tulisan 'NEW!' akan muncul di pojok kanan bawahnya. Seru kan? Ini cuma sekilas aja, nanti kita kupas tuntas `Stack` ini di sesi berikutnya!
Latihan: Penyelamat Deadline!
Gimana, otak udah ngebul tapi hati senang? Nah, biar makin jago, coba kerjain latihan receh ini!
- Buatlah aplikasi Flutter baru.
- Di `body` dari `Scaffold` kamu, buat sebuah layout yang mirip kartu nama.
- Kartu nama tersebut harus memiliki:
- Sebuah `Container` sebagai wadah utama dengan warna latar belakang (bebas) dan padding yang cukup.
- Di dalamnya, gunakan `Column` untuk menyusun item secara vertikal.
- Item pertama adalah `Image.network` (ambil gambar avatar lucu dari internet, misal
https://i.pravatar.cc/150) yang dibungkus `Container` dengan `width` dan `height` tertentu serta `borderRadius` agar gambarnya bulat atau setidaknya melengkung manis. - Di bawah gambar, ada `Text` nama kamu (atau nama alias programmer-mu) dengan style `TextStyle` yang bold dan ukuran besar.
- Di bawah nama, ada `Text` deskripsi singkat atau "jabatan" kamu (misal: "Frontend Developer | Tukang Ngopi", "Backend Engineer | Spesialis Bug Hunting", dsb.) dengan `TextStyle` yang agak miring (`fontStyle: FontStyle.italic`).
- Terakhir, tambahkan `Row` di bagian paling bawah kartu yang berisi dua `ElevatedButton`. Satu tombol untuk "Follow Me!" dan satu lagi untuk "Kirim Kopi!". Pastikan kedua tombol ini di-wrap dengan `Expanded` agar mereka berbagi ruang secara merata dan memenuhi lebar `Row` tersebut. Kasih jarak dikit antara dua tombol pakai `SizedBox`.
- Pastikan semua widget teratur dan jaraknya pas menggunakan `SizedBox` atau properti `padding`/`margin` di `Container`.
Jangan takut error! Kalau ada error, itu tandanya kamu hidup dan belajar. Anggap aja itu sapaan dari komputer. Selamat ngoding, jangan lupa ngopi!
.png)