Pada Level 5, kita sudah mempelajari bahwa hampir seluruh tampilan Flutter dibangun dari widget.
Kita mengenal:
TextImageContainerRowColumnStackExpandedListViewStatelessWidgetStatefulWidget- custom widget
- widget tree
Namun, memahami widget saja belum cukup, maka diperlukan layout dan responsive UI Flutter. Bayangkan Anda sudah berhasil membuat halaman profil seperti ini:
┌─────────────────────┐
│ Profil │
├─────────────────────┤
│ Avatar │
│ │
│ Nama Pengguna │
│ Flutter Developer │
│ │
│ [ Edit Profil ] │
└─────────────────────┘
Di layar smartphone, semuanya mungkin terlihat bagus. Tetapi bagaimana jika aplikasi dibuka pada:
- smartphone kecil?
- smartphone besar?
- tablet?
- layar landscape?
- desktop?
- browser dengan ukuran window yang dapat diubah?
- mode split-screen?
Jika layout hanya dirancang untuk satu ukuran layar, UI bisa mengalami masalah.
Contohnya:
Text terlalu panjang
↓
Overflow
Button terlalu lebar
↓
Layout rusak
Card terlalu besar
↓
Tampilan tidak proporsional
Column terlalu tinggi
↓
Konten terpotong
Inilah alasan mengapa setelah mempelajari widget, kita perlu memahami layout dan responsive UI.
Flutter dirancang agar aplikasi dapat bekerja pada berbagai ukuran layar dan platform. Dokumentasi Flutter membedakan konsep responsive sebagai kemampuan UI menyesuaikan penempatan elemen dengan ruang yang tersedia, sedangkan adaptive berkaitan dengan memilih UI atau pola interaksi yang tepat untuk ruang tersebut.
Materi layout dan responsive UI Flutter ini merupakan pembelajaran Level 6 dari Roadmap Belajar Flutter dari Nol Sampai Siap Kerja yang dibahas pada situs Raja Putra Media.
Apa Itu Layout dalam Flutter?
Layout adalah proses menentukan bagaimana widget ditempatkan, diberi ukuran, disejajarkan, dan disusun di dalam UI. Flutter membangun layout dengan menggunakan widget.
Contohnya:
Column(
children: [
const Text('Nama'),
const Text('Email'),
ElevatedButton(
onPressed: () {},
child: const Text('Simpan'),
),
],
)
Kita bisa membayangkan:
Column
│
├── Text
├── Text
└── ElevatedButton
Column menentukan bahwa widget-widget tersebut disusun secara vertikal.
Begitu pula:
Row(
children: [
const Icon(Icons.email),
const SizedBox(width: 8),
const Text('Email'),
],
)
menghasilkan susunan horizontal.
Flutter menjelaskan bahwa layout dibangun dengan mengombinasikan widget sederhana menjadi struktur yang lebih kompleks. Bahkan widget yang tidak terlihat secara langsung, seperti Row, Column, dan GridView, merupakan bagian penting dari sistem layout.
Memahami Konsep Constraints Flutter
Salah satu konsep terpenting dalam layout Flutter adalah constraints.
Banyak error layout yang dialami pemula sebenarnya berasal dari belum memahami bagaimana constraints bekerja.
Aturan sederhananya adalah:
Constraints go down. Sizes go up. Parent sets position.
Artinya:
Parent
↓
memberikan constraints
↓
Child menentukan ukuran
↓
Parent menentukan posisi
Flutter menjelaskan bahwa setiap widget menerima constraints dari parent berupa batas minimum dan maksimum untuk lebar serta tinggi. Widget kemudian menentukan ukurannya berdasarkan batas tersebut, sementara parent menentukan posisinya.
Misalnya:
Center(
child: Container(
width: 200,
height: 100,
),
)
Secara sederhana:
Screen
↓
Center
↓
Container
Screen memberikan ruang kepada Center. Kemudian Center memberikan ruang yang sesuai kepada Container.
Container mencoba menggunakan ukuran:
200 × 100
selama ukuran tersebut masih diperbolehkan oleh constraints parent.
Mengapa Constraints Penting?
Misalnya Anda menulis:
Container(
width: 500,
)
Anda mungkin berpikir container pasti memiliki lebar 500.
Belum tentu. Jika parent hanya memberikan ruang selebar 300 logical pixels, widget tidak bisa begitu saja memaksa menggunakan 500.
Inilah salah satu alasan mengapa layout Flutter kadang terlihat berbeda dari yang dibayangkan.
Masalah yang sering muncul antara lain:
RenderFlex overflowed
atau:
BoxConstraints forces an infinite width
Biasanya error seperti ini berkaitan dengan hubungan antara parent, child, constraints, dan widget layout. Karena itu, jangan langsung menambahkan Container, SizedBox, atau angka tertentu setiap kali layout bermasalah.
Pertama-tama pahami:
Widget tersebut menerima constraints seperti apa?
Row dan Column
Dua widget yang akan sangat sering digunakan dalam layout Flutter adalah:
RowColumn
Row
Row menyusun child secara horizontal.
Row(
children: [
const Icon(Icons.person),
const SizedBox(width: 8),
const Text('Andi'),
],
)
Visualnya:
[Icon] Andi
Column
Column menyusun child secara vertikal.
Column(
children: [
const Text('Andi'),
const Text('Flutter Developer'),
const Text('Indonesia'),
],
)
Visual:
Andi
Flutter Developer
Indonesia
Keduanya menjadi dasar hampir semua layout Flutter.
MainAxisAlignment dan CrossAxisAlignment
Setelah memahami Row dan Column, Anda perlu memahami alignment.
Contoh:
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Nama'),
const Text('Email'),
],
)
Pada Column:
- main axis = vertikal
- cross axis = horizontal
Sedangkan pada Row:
- main axis = horizontal
- cross axis = vertikal
Contoh:
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Produk'),
const Text('Rp100.000'),
],
)
Hasil konseptual:
Produk Rp100.000
Pemahaman axis ini sangat penting sebelum masuk ke responsive layout.
Expanded untuk Membagi Ruang
Expanded digunakan untuk membuat child mengisi ruang yang tersedia dalam Row, Column, atau Flex.
Contoh:
Row(
children: [
Expanded(
child: Container(
height: 100,
),
),
const SizedBox(width: 16),
Expanded(
child: Container(
height: 100,
),
),
],
)
Konsepnya:
┌────────────┬────────────┐
│ │ │
│ Child │ Child │
│ │ │
└────────────┴────────────┘
Kedua child berbagi ruang yang tersedia.
Ini jauh lebih fleksibel dibanding menetapkan:
width: 150
untuk setiap perangkat.
Flexible
Flexible memiliki konsep yang mirip dengan Expanded, tetapi memberikan fleksibilitas lebih besar kepada child dalam menggunakan ruang yang tersedia.
Contoh:
Row(
children: [
Flexible(
child: Text(
'Judul produk yang cukup panjang',
),
),
const Icon(Icons.arrow_forward),
],
)
Widget seperti Flexible berguna ketika konten dapat memiliki ukuran yang berbeda dan kita ingin mencegah layout menjadi terlalu kaku.
Wrap untuk Layout yang Fleksibel
Row akan mencoba menyusun semua child dalam satu baris. Masalah muncul jika jumlah child terlalu banyak.
Contohnya:
Flutter
Dart
Firebase
Git
GitHub
REST API
Jika dipaksa menggunakan Row, bisa terjadi overflow.
Gunakan Wrap:
Wrap(
spacing: 8,
runSpacing: 8,
children: [
Chip(label: const Text('Flutter')),
Chip(label: const Text('Dart')),
Chip(label: const Text('Firebase')),
Chip(label: const Text('Git')),
Chip(label: const Text('GitHub')),
],
)
Wrap dapat memindahkan child ke baris berikutnya ketika ruang horizontal tidak mencukupi.
Konsepnya:
Flutter Dart Firebase
Git GitHub REST API
Ini sangat berguna untuk:
- tag
- chip
- kategori
- filter
- tombol
- daftar fitur
Apa Itu Responsive UI?
Responsive UI adalah pendekatan untuk membuat tampilan yang dapat menyesuaikan diri terhadap ruang yang tersedia. Misalnya halaman dashboard.
Pada layar kecil:
┌───────────────┐
│ Header │
├───────────────┤
│ Card 1 │
├───────────────┤
│ Card 2 │
├───────────────┤
│ Card 3 │
└───────────────┘
Pada layar lebih besar:
┌─────────────────────────────┐
│ Header │
├──────────┬──────────┬───────┤
│ Card 1 │ Card 2 │Card 3 │
└──────────┴──────────┴───────┘
Kontennya sama. Namun cara penyusunannya berubah. Inilah inti responsive layout.
Responsive Bukan Sekadar Mengecilkan UI
Kesalahan umum adalah menganggap responsive berarti:
“Kalau layar kecil, semua ukuran diperkecil.”
Tidak selalu. Responsive design lebih tepat dipahami sebagai kemampuan menyesuaikan susunan dan penggunaan ruang.
Misalnya:
Mobile
Bottom Navigation
↓
Tablet/Desktop
Navigation Rail
Atau:
Mobile
1 column
↓
Tablet
2 columns
↓
Desktop
3–4 columns
Flutter sendiri memberikan contoh adaptive layout yang menggunakan sidebar dan detail secara berdampingan pada layar besar, sementara layar kecil menggunakan pola navigasi yang berbeda.
Responsive vs Adaptive
Dua istilah ini sering digunakan bersama.
Responsive
Fokus pada: Bagaimana UI menyesuaikan diri dengan ruang yang tersedia?
Contohnya:
400 px
→ 1 kolom
800 px
→ 2 kolom
1200 px
→ 3 kolom
Adaptive
Fokus pada: UI seperti apa yang paling sesuai digunakan pada ruang dan konteks tersebut?
Contohnya:
Layar kecil
→ NavigationBar
Layar besar
→ NavigationRail
Jadi:
Responsive
= menyesuaikan layout
Adaptive
= memilih pengalaman UI yang sesuai
Flutter sendiri menjelaskan bahwa responsive berkaitan dengan membuat UI “fit” terhadap ruang, sementara adaptive berkaitan dengan membuat UI tetap usable pada ruang tersebut.
Jangan Menentukan Layout Hanya Berdasarkan Jenis Perangkat
Pemula sering membuat logika seperti:
if (isPhone) {
// mobile
} else {
// desktop
}
Pendekatan seperti ini tidak selalu tepat.
Bayangkan aplikasi Flutter berjalan pada:
- tablet dalam split-screen
- desktop dengan window kecil
- Chromebook
- browser
- foldable
- monitor besar dengan window yang tidak fullscreen
Jenis perangkat tidak selalu menunjukkan berapa banyak ruang yang sebenarnya tersedia untuk aplikasi.
Dokumentasi Flutter merekomendasikan agar keputusan layout lebih didasarkan pada ukuran window yang tersedia, bukan sekadar apakah perangkat disebut phone atau tablet.
Menggunakan MediaQuery
Salah satu cara mendapatkan informasi mengenai ukuran window aplikasi adalah MediaQuery.
Pada Flutter modern, jika yang dibutuhkan hanya ukuran window, dokumentasi merekomendasikan MediaQuery.sizeOf(context) karena lebih spesifik dibanding mengambil seluruh data MediaQuery.
Contoh:
final size = MediaQuery.sizeOf(context);
final width = size.width;
final height = size.height;
Kemudian:
if (width < 600) {
// Layout kecil
} else {
// Layout besar
}
Contoh sederhana:
Widget build(BuildContext context) {
final width = MediaQuery.sizeOf(context).width;
return width < 600
? const MobileLayout()
: const LargeLayout();
}
Mengapa Tidak Selalu Menggunakan MediaQuery?
MediaQuery.sizeOf memberikan ukuran window aplikasi. Namun terkadang yang ingin diketahui bukan ukuran seluruh window.
Misalnya Anda mempunyai:
┌─────────────────────────────┐
│ Header │
├─────────────────────────────┤
│ Sidebar │ Content │
│ │ │
│ │ Widget Anda │
│ │ │
└─────────────────────────────┘
Widget di bagian Content mungkin hanya mendapatkan sebagian ruang. Untuk kondisi seperti ini, LayoutBuilder sering lebih tepat.
Mengenal LayoutBuilder
LayoutBuilder memberikan informasi tentang constraints yang diterima widget dari parent.
Contoh:
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const MobileLayout();
}
return const DesktopLayout();
},
)
Perbedaannya secara sederhana:
MediaQuery.sizeOf
↓
Ukuran window aplikasi
LayoutBuilder
↓
Ruang yang tersedia untuk widget tersebut
Flutter secara resmi merekomendasikan MediaQuery.sizeOf ketika keputusan layout didasarkan pada ukuran seluruh app window, sedangkan LayoutBuilder cocok ketika keputusan layout bergantung pada ruang yang diberikan kepada widget tertentu.
MediaQuery vs LayoutBuilder
| Kebutuhan | Pilihan |
|---|---|
| Mengetahui ukuran window aplikasi | MediaQuery.sizeOf |
| Mengetahui constraints widget | LayoutBuilder |
| Layout berdasarkan area tertentu | LayoutBuilder |
| Informasi accessibility/window lainnya | MediaQuery |
| Responsive halaman penuh | MediaQuery.sizeOf |
| Responsive reusable component | LayoutBuilder |
Jangan menganggap salah satu selalu lebih baik. Gunakan berdasarkan kebutuhan.
Membuat Breakpoint
Breakpoint adalah batas ukuran yang digunakan untuk menentukan perubahan layout.
Contohnya:
< 600
Mobile
600 – 1023
Tablet / Medium
≥ 1024
Large
Contoh implementasi:
LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth;
if (width < 600) {
return const MobileLayout();
}
if (width < 1024) {
return const TabletLayout();
}
return const DesktopLayout();
},
)
Namun jangan menganggap angka tersebut sebagai aturan universal.
Breakpoint harus ditentukan berdasarkan kapan desain Anda membutuhkan perubahan layout, bukan semata-mata berdasarkan nama perangkat.
Dokumentasi Flutter bahkan memberikan contoh bahwa Material merekomendasikan pola seperti bottom navigation untuk window di bawah 600 logical pixels dan navigation rail pada ukuran 600 atau lebih untuk kasus tertentu. Ini adalah contoh breakpoint desain, bukan aturan bahwa semua aplikasi harus menggunakan angka tersebut.
Contoh Responsive Card
Misalnya kita ingin menampilkan daftar artikel.
Pada layar kecil:
┌───────────────┐
│ Article 1 │
├───────────────┤
│ Article 2 │
├───────────────┤
│ Article 3 │
└───────────────┘
Pada layar besar:
┌────────┬────────┬────────┐
│ Art. 1 │ Art. 2 │ Art. 3 │
└────────┴────────┴────────┘
Implementasinya dapat menggunakan LayoutBuilder:
LayoutBuilder(
builder: (context, constraints) {
int columns;
if (constraints.maxWidth < 600) {
columns = 1;
} else if (constraints.maxWidth < 1000) {
columns = 2;
} else {
columns = 3;
}
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
),
itemCount: articles.length,
itemBuilder: (context, index) {
return ArticleCard(
article: articles[index],
);
},
);
},
)
Inilah contoh nyata bagaimana widget Level 5 dapat digunakan untuk membuat responsive UI.
SafeArea
Selain ukuran layar, kita juga perlu memperhatikan area yang mungkin tertutup oleh sistem operasi.
Contohnya:
- status bar
- notch
- camera cutout
- rounded display
- system UI
Flutter menyediakan SafeArea.
Contoh:
Scaffold(
body: SafeArea(
child: MyContent(),
),
)
SafeArea memberikan inset agar child tidak tertutup oleh bagian fisik atau UI sistem yang mengganggu area tampilan. Flutter menjelaskan bahwa SafeArea menggunakan informasi dari MediaQuery untuk menentukan inset yang sesuai.
Untuk banyak halaman aplikasi, membungkus content utama dengan SafeArea merupakan titik awal yang baik.
AspectRatio
AspectRatio berguna ketika kita ingin mempertahankan perbandingan lebar dan tinggi.
Misalnya thumbnail video:
AspectRatio(
aspectRatio: 16 / 9,
child: Container(),
)
Maka area akan berusaha mempertahankan rasio:
16 : 9
Ini sangat berguna untuk:
- video
- thumbnail
- banner
- image card
- preview
FractionallySizedBox
FractionallySizedBox memungkinkan child menggunakan persentase tertentu dari ruang yang tersedia.
Contoh:
FractionallySizedBox(
widthFactor: 0.8,
child: Container(
height: 100,
),
)
Artinya widget mencoba menggunakan sekitar:
80% dari lebar yang tersedia
Widget seperti ini dapat membantu ketika desain membutuhkan ukuran relatif, bukan angka fixed.
Flutter memasukkan FractionallySizedBox, Expanded, Align, AspectRatio, dan berbagai widget lainnya ke dalam kelompok layout widgets.
Hindari Terlalu Banyak Ukuran Fixed
Perhatikan kode seperti:
Container(
width: 350,
height: 200,
)
Angka fixed tidak selalu salah. Namun jika hampir semua elemen menggunakan ukuran fixed, UI dapat menjadi sulit beradaptasi.
Contohnya:
Container(
width: 350,
child: Text(...),
)
bisa terlihat baik pada satu perangkat.
Tetapi ketika ruang hanya:
320 logical pixels
layout bisa bermasalah.
Lebih baik gunakan kombinasi:
constraints
+
Expanded
+
Flexible
+
Padding
+
Wrap
+
LayoutBuilder
+
responsive breakpoint
sesuai kebutuhan.
Jangan Membuat Semua Layout Full Width
Pada desktop atau layar sangat besar, membuat semua content memenuhi seluruh lebar layar juga bukan selalu pilihan yang baik.
Bayangkan artikel dengan teks selebar:
┌──────────────────────────────────────────────────────────────┐
│ teks sangat panjang......................................... │
│ ............................................................ │
└──────────────────────────────────────────────────────────────┘
Membaca teks sepanjang itu kurang nyaman.
Lebih baik memberikan batas:
┌──────────────────────────────────────────────────────────────┐
│ ┌──────────────────────┐ │
│ │ Konten dibatasi │ │
│ │ agar mudah dibaca │ │
│ └──────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Dokumentasi Flutter juga menyarankan agar aplikasi tidak sekadar menggunakan seluruh ruang horizontal pada layar besar.
Contoh Layout Responsif Sederhana
Mari membuat halaman yang memiliki dua mode.
Layar kecil
┌─────────────────┐
│ AppBar │
├─────────────────┤
│ Profile │
│ │
│ Statistics │
│ │
│ Activities │
└─────────────────┘
Layar besar
┌─────────────────────────────────────┐
│ AppBar │
├──────────────┬──────────────────────┤
│ Profile │ Statistics │
│ │ │
│ │ Activities │
└──────────────┴──────────────────────┘
Kodenya:
class DashboardPage extends StatelessWidget {
const DashboardPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Dashboard'),
),
body: LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 700) {
return const Column(
children: [
ProfileSection(),
StatisticsSection(),
ActivitiesSection(),
],
);
}
return const Row(
children: [
Expanded(
child: ProfileSection(),
),
Expanded(
flex: 2,
child: Column(
children: [
StatisticsSection(),
ActivitiesSection(),
],
),
),
],
);
},
),
);
}
}
Yang berubah bukan datanya. Yang berubah adalah struktur layout.
Responsive Navigation
Responsive UI tidak hanya berkaitan dengan ukuran card atau jumlah kolom. Navigasi juga perlu beradaptasi.
Misalnya:
Mobile
NavigationBar
↓
Large Screen
NavigationRail
Untuk aplikasi yang lebih kompleks, Anda dapat membuat struktur seperti:
Small window
↓
NavigationBar
↓
Content
Large window
↓
NavigationRail
↓
Content
Flutter menggunakan pola seperti ini dalam contoh adaptive layout resminya.
Hindari Bergantung pada Orientation Saja
Pemula sering membuat:
if (orientation == Orientation.landscape) {
// desktop layout
} else {
// mobile layout
}
Pendekatan ini tidak selalu akurat. Landscape tidak otomatis berarti tersedia ruang yang besar.
Misalnya:
Tablet landscape
dapat memiliki ruang yang sangat besar.
Tetapi:
Phone landscape
tetap mungkin memiliki ruang terbatas secara vertikal.
Flutter menyarankan agar keputusan layout tidak hanya bergantung pada orientation. Lebih baik mengukur ruang yang benar-benar tersedia menggunakan MediaQuery.sizeOf atau LayoutBuilder.
Pola Berpikir Responsive UI
Daripada berpikir:
Jika Android → layout A
Jika iOS → layout B
Jika tablet → layout C
mulailah berpikir:
Berapa ruang yang tersedia?
↓
Apa kebutuhan kontennya?
↓
Apakah layout masih nyaman?
↓
Jika tidak, ubah struktur layout.
Ini merupakan pola berpikir yang jauh lebih fleksibel.
Best Practice Responsive Flutter
1. Pecah widget menjadi komponen kecil
Jangan membuat satu widget berisi seluruh halaman.
Gunakan:
Dashboard
├── Header
├── Summary
├── Chart
├── RecentActivity
└── Navigation
Flutter juga merekomendasikan pemecahan widget kompleks menjadi bagian yang lebih kecil karena dapat mempermudah penerapan adaptive UI.
2. Gunakan constraints sebagai dasar
Jangan langsung menggunakan banyak angka fixed. Pahami terlebih dahulu ruang yang tersedia.
3. Gunakan LayoutBuilder untuk komponen lokal
Jika sebuah widget harus beradaptasi berdasarkan ruang yang diberikan parent:
LayoutBuilder(...)
adalah pilihan yang tepat.
4. Gunakan MediaQuery.sizeOf untuk ukuran window
Jika keputusan layout bergantung pada ukuran window aplikasi:
MediaQuery.sizeOf(context)
dapat digunakan.
5. Jangan bergantung pada jenis perangkat
Hindari asumsi:
Phone = kecil
Tablet = besar
Desktop = sangat besar
Ukuran window aplikasi dapat berubah.
6. Jangan mengunci orientation tanpa alasan kuat
Flutter merekomendasikan agar aplikasi adaptive tidak dikunci hanya pada portrait karena perangkat modern dapat menggunakan multi-window, foldable, landscape, dan berbagai konfigurasi lainnya.
7. Uji pada berbagai ukuran
Minimal uji:
Small Phone
Large Phone
Tablet
Landscape
Desktop
Resize Window
Responsive UI tidak cukup diuji hanya pada satu emulator.
Latihan Level 6
Sekarang buat sebuah Dashboard Responsive Flutter.
Target:
Mobile
┌─────────────────┐
│ Dashboard │
├─────────────────┤
│ Welcome Card │
├─────────────────┤
│ Statistic 1 │
├─────────────────┤
│ Statistic 2 │
├─────────────────┤
│ Statistic 3 │
├─────────────────┤
│ Activity │
└─────────────────┘
Tablet
┌──────────────────────────┐
│ Dashboard │
├────────────┬─────────────┤
│ Welcome │ Statistics │
│ Card │ │
├────────────┴─────────────┤
│ Activity │
└──────────────────────────┘
Desktop
┌────────────────────────────────────┐
│ Dashboard │
├──────────┬────────────┬────────────┤
│ Welcome │ Statistic │ Statistic │
├──────────┴────────────┴────────────┤
│ Activity │
└────────────────────────────────────┘
Gunakan minimal:
ScaffoldSafeAreaRowColumnExpandedFlexiblePaddingLayoutBuilderMediaQuery.sizeOfWrap- custom widgets
Tantangan Tambahan
Setelah dashboard selesai, tambahkan:
Challenge 1 — Responsive Grid
Buat daftar produk:
Mobile
1 kolom
Tablet
2 kolom
Desktop
3–4 kolom
Challenge 2 — Responsive Navigation
Buat:
Mobile
NavigationBar
Desktop
NavigationRail
Challenge 3 — Responsive Profile
Pada layar kecil:
Avatar
Nama
Bio
Button
Pada layar besar:
Avatar | Nama + Bio + Button
Challenge 4 — Resize Browser
Jika Anda menjalankan Flutter Web, ubah ukuran browser secara manual. Perhatikan bagaimana layout berubah.
Ini merupakan latihan yang sangat bagus untuk memahami konsep responsive UI.
Checklist Setelah Menyelesaikan Level 6
Sebelum melanjutkan ke Level 7, pastikan Anda sudah memahami:
- Apa itu layout Flutter
- Apa itu constraints
- Prinsip “constraints go down, sizes go up, parent sets position”
- Cara menggunakan
Row - Cara menggunakan
Column MainAxisAlignmentCrossAxisAlignmentExpandedFlexibleWrapAspectRatioFractionallySizedBoxSafeArea- Konsep responsive UI
- Konsep adaptive UI
- Perbedaan responsive dan adaptive
MediaQuery.sizeOfLayoutBuilder- Konsep breakpoint
- Responsive grid
- Responsive navigation
- Menghindari layout berdasarkan jenis perangkat
- Menghindari ketergantungan pada orientation
- Menguji UI pada berbagai ukuran layar
Jika sebagian besar poin sudah dikuasai, Anda sudah memiliki fondasi UI Flutter yang jauh lebih kuat.
Apa yang Dipelajari Setelah Responsive UI?
Sampai Level 6, roadmap kita sudah membangun fondasi UI dari bawah:
Level 4 - Struktur Project Flutter
↓
Level 5 - Widget
↓
Level 6 - Layout & Responsive UI
Namun ada satu hal penting yang belum dibahas secara mendalam. Bagaimana jika UI harus berubah ketika pengguna melakukan sesuatu?
Misalnya:
User menekan tombol
↓
Counter bertambah
User memilih checkbox
↓
Checkbox berubah
User login
↓
UI berubah
Data sedang loading
↓
Tampilkan progress indicator
Data selesai
↓
Tampilkan hasil
Di sinilah kita mulai masuk ke konsep state dan bagaimana beberapa bagian aplikasi saling berpindah antar halaman.
Karena itu, tahap berikutnya dalam roadmap adalah: Level 7 — Navigation & State Management
Pada Level 7, kita akan mulai membahas:
- navigation Flutter
Navigator- route
- named route
- passing data antar halaman
- kembali ke halaman sebelumnya
- state lokal
- state aplikasi
setState- memahami kapan state perlu dipindahkan
- dasar state management
- pengenalan Provider, Riverpod, atau pendekatan state management lainnya
- pola pengelolaan state dalam aplikasi nyata
Dengan begitu, perjalanan belajar akan berkembang dari:
Membangun UI
↓
Membuat UI responsif
↓
Mengelola perubahan UI
↓
Menghubungkan antar halaman
↓
Mengelola state aplikasi
Kesimpulan
Mempelajari layout dan responsive UI merupakan tahap penting dalam perjalanan menjadi Flutter Developer.
Menguasai widget Flutter: Jenis, Fungsi, dan Contohnya pada Level 5 mengajarkan kita apa yang digunakan untuk membangun UI. Level 6 mengajarkan bagaimana widget-widget tersebut disusun dan bagaimana layout beradaptasi terhadap ruang yang tersedia.
Konsep terpenting yang perlu dikuasai adalah constraints:
Constraints go down
Sizes go up
Parent sets position
Kemudian gunakan widget layout sesuai kebutuhan:
Row
Column
Expanded
Flexible
Wrap
Stack
AspectRatio
Untuk responsive UI, jangan hanya berpikir mengenai jenis perangkat.
Jangan hanya bertanya:
“Ini HP atau tablet?”
Pertanyaan yang lebih tepat adalah:
“Berapa banyak ruang yang tersedia untuk aplikasi saya?”
Gunakan:
MediaQuery.sizeOf
ketika Anda perlu mengetahui ukuran window aplikasi, dan:
LayoutBuilder
ketika keputusan layout bergantung pada ruang yang diberikan kepada widget tertentu. Pendekatan ini sejalan dengan panduan adaptive Flutter saat ini.
Gunakan breakpoint berdasarkan kebutuhan desain, bukan sekadar berdasarkan label device.
Dan jangan lupa menguji aplikasi pada berbagai kondisi:
Small Phone
↓
Large Phone
↓
Tablet
↓
Landscape
↓
Desktop
↓
Resizable Window
Tujuan akhirnya bukan membuat satu UI yang dipaksa cocok untuk semua perangkat.
Tujuannya adalah membuat UI yang mampu beradaptasi secara alami terhadap ruang, konteks, dan cara pengguna berinteraksi dengan aplikasi.
Setelah konsep ini dikuasai, Anda sudah memiliki fondasi yang cukup untuk mulai membuat aplikasi Flutter yang tidak hanya terlihat bagus pada satu layar, tetapi juga siap menghadapi berbagai ukuran dan konfigurasi perangkat.
Selanjutnya kita masuk ke Level 7 — Navigation dan State Management Flutter, yaitu tahap ketika aplikasi mulai terasa benar-benar interaktif dan memiliki alur penggunaan yang lebih kompleks.
- adaptive UI Flutter
- belajar Flutter
- belajar Flutter dari nol
- breakpoint Flutter
- constraints Flutter
- desain aplikasi Flutter
- Expanded Flutter
- Flexible Flutter
- Flutter responsive design
- Flutter untuk pemula
- layout Flutter
- LayoutBuilder Flutter
- MediaQuery Flutter
- MediaQuery.sizeOf Flutter
- responsive Flutter
- responsive UI Flutter
- SafeArea Flutter
- tutorial Flutter
- Wrap Flutter
Tinggalkan komentar