Beranda Coding Layout dan Responsive UI Flutter: Panduan untuk Pemula
CodingFlutter

Layout dan Responsive UI Flutter: Panduan untuk Pemula

Pelajari layout dan responsive UI Flutter dari nol, mulai dari constraints, Row, Column, Expanded, Flexible, MediaQuery, LayoutBuilder, SafeArea, breakpoint, hingga adaptive UI.

Bagikan
layout responsive ui flutter
Bagikan

Pada Level 5, kita sudah mempelajari bahwa hampir seluruh tampilan Flutter dibangun dari widget.

Kita mengenal:

  • Text
  • Image
  • Container
  • Row
  • Column
  • Stack
  • Expanded
  • ListView
  • StatelessWidget
  • StatefulWidget
  • 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:

  • Row
  • Column

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
Baca juga:  Memahami Flutter dan Ekosistemnya untuk Pemula

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

KebutuhanPilihan
Mengetahui ukuran window aplikasiMediaQuery.sizeOf
Mengetahui constraints widgetLayoutBuilder
Layout berdasarkan area tertentuLayoutBuilder
Informasi accessibility/window lainnyaMediaQuery
Responsive halaman penuhMediaQuery.sizeOf
Responsive reusable componentLayoutBuilder

Jangan menganggap salah satu selalu lebih baik. Gunakan berdasarkan kebutuhan.

Baca juga:  Sejarah PHP dan Perkembangannya dari Masa ke Masa

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.

Baca juga:  Struktur Project Flutter: Fungsi Folder dan File untuk Pemula

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:

  • Scaffold
  • SafeArea
  • Row
  • Column
  • Expanded
  • Flexible
  • Padding
  • LayoutBuilder
  • MediaQuery.sizeOf
  • Wrap
  • 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
  • MainAxisAlignment
  • CrossAxisAlignment
  • Expanded
  • Flexible
  • Wrap
  • AspectRatio
  • FractionallySizedBox
  • SafeArea
  • Konsep responsive UI
  • Konsep adaptive UI
  • Perbedaan responsive dan adaptive
  • MediaQuery.sizeOf
  • LayoutBuilder
  • 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.

Bagikan

Tinggalkan komentar

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Artikel Terkait
database flutter
CodingFlutter

Database Flutter: SQLite, Local Storage, dan CRUD untuk Pemula

Pelajari database Flutter dan local storage dari nol, mulai dari SQLite, shared_preferences,...

rest api flutter
CodingFlutter

REST API Flutter: Panduan HTTP, JSON, dan Pengolahan Data

Pelajari REST API Flutter dari nol, mulai dari HTTP request, GET, POST,...

navigation dan state management flutter
CodingFlutter

Navigation dan State Management Flutter untuk Pemula

Pelajari Navigation dan State Management Flutter dari nol, mulai dari Navigator, Route,...

menguasai widget flutter
CodingFlutter

Menguasai Widget Flutter: Jenis, Fungsi, dan Contohnya untuk Pemula

Pelajari widget Flutter dari nol, mulai dari widget tree, StatelessWidget, StatefulWidget, BuildContext,...