â˜€ī¸Siang
Mobile Development

Cheatsheet Flutter & Dart: Referensi Cepat Widget, State, dan API

GRATIS

Referensi cepat Dart syntax, Flutter widgets, state management, navigasi, HTTP request, dan JSON parsing dalam satu halaman



1. Dart Variables & Types

💡 Tips

Gunakan final untuk variabel yang hanya diinisialisasi sekali, dan const untuk nilai yang sudah diketahui saat compile-time.

Deklarasi Variabel

// Tipe eksplisit
String nama = 'Budi';
int umur = 25;
double tinggi = 175.5;
bool aktif = true;

// Tipe dinamis
var kota = 'Jakarta';        // Inferred sebagai String
dynamic data = 'bisa apa saja'; // Bisa berubah tipe

// final & const
final waktu = DateTime.now();  // Runtime const, tidak bisa diubah
const pi = 3.14159;            // Compile-time const

// Nullable (Dart null safety)
String? alamat;                // Bisa null
int? nilai;                    // Bisa null
String nama2 = 'Wajib isi';    // Tidak boleh null

// Null safety operators
print(alamat?.length);         // Null-aware access
String namaFinal = nama2 ?? 'Default'; // Null coalescing
String namaUpper = nama2.toUpperCase(); // Cascade
alamat ??= 'Belum diisi';     // Null-aware assignment

Tipe Data Dart

TipeKeteranganContoh
intBilangan bulatint x = 42;
doubleDesimaldouble y = 3.14;
numParent int/doublenum z = 7;
StringTeksString s = 'hello';
boolBooleanbool b = true;
ListArrayList<int> a = [1,2,3];
MapKey-value pairsMap<String,int> m = {'a':1};
SetUnique collectionSet<int> s = {1,2,3};
dynamicTipe apapundynamic x = 'abc';
varInferred typevar x = 10;
finalSekali assignfinal x = getValue();
constCompile-time constantconst x = 42;

2. Dart Functions

// Fungsi dasar
int tambah(int a, int b) {
  return a + b;
}

// Arrow function (satu expression)
int kali(int a, int b) => a * b;

// Named parameters
void greet({required String nama, String salam = 'Halo'}) {
  print('$salam, $nama!');
}
greet(nama: 'Budi');               // Halo, Budi!
greet(nama: 'Budi', salam: 'Hi');  // Hi, Budi!

// Optional positional parameters
void log(String message, [String? prefix]) {
  print('${prefix ?? 'LOG'}: $message');
}
log('Server started');          // LOG: Server started
log('Server started', 'INFO');  // INFO: Server started

// Anonymous function / lambda
var list = [1, 2, 3, 4, 5];
var genap = list.where((n) => n % 2 == 0).toList();
// [2, 4]

// Higher-order function
List<int> apply(List<int> list, int Function(int) fn) {
  return list.map(fn).toList();
}
var hasil = apply([1, 2, 3], (x) => x * 2);
// [2, 4, 6]

// Cascade notation
var buffer = StringBuffer()
  ..write('Hello ')
  ..write('World')
  ..write('!');
print(buffer.toString()); // Hello World!

3. Dart Async/Await & Future

âš ī¸ Peringatan

Selalu gunakan async/await untuk operasi async di Flutter. Hindari .then() chaining yang membuat kode sulit dibaca.

// Future - asynchronous computation
Future<String> fetchData() async {
  // Simulasi network request
  await Future.delayed(Duration(seconds: 2));
  return 'Data loaded!';
}

// Async/Await
void loadData() async {
  try {
    String data = await fetchData();
    print(data); // Data loaded!
  } catch (e) {
    print('Error: $e');
  }
}

// Future chaining dengan .then()
fetchData()
  .then((data) => print(data))
  .catchError((e) => print('Error: $e'));

// Stream - multiple async values
Stream<int> countStream(int max) async* {
  for (int i = 1; i <= max; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

// Mendengarkan Stream
void listenStream() async {
  await for (int value in countStream(5)) {
    print('Count: $value');
  }
}

// StreamBuilder di Flutter
// StreamBuilder<int>(
//   stream: countStream(10),
//   builder: (context, snapshot) {
//     if (snapshot.hasData) {
//       return Text('Count: ${snapshot.data}');
//     }
//     return CircularProgressIndicator();
//   },
// )

// Completer - manual future completion
import 'dart:async';
Future<String> getAuth() {
  final completer = Completer<String>();
  // Misalnya callback-based API
  onAuthSuccess((token) {
    completer.complete(token);
  });
  return completer.future;
}

4. Dart Collections

List

// List
var buah = ['apel', 'jeruk', 'mangga'];
buah.add('pisang');
buah.addAll(['anggur', 'melon']);
buah.remove('jeruk');
buah.removeAt(0);
buah.insert(0, 'durian');

// List properties & methods
buah.length;          // Jumlah elemen
buah.isEmpty;         // true jika kosong
buah.isNotEmpty;      // true jika ada isi
buah.first;           // Elemen pertama
buah.last;            // Elemen terakhir
buah.contains('apel'); // true/false
buah.sublist(0, 2);   // [durian, mangga]
buah.shuffle();       // Acak urutan

// Spread operator & collection if/for
var a = [1, 2, 3];
var b = [0, ...a];           // [0, 1, 2, 3]
var c = [0, ...?a];          // null-safe spread

var showItem = true;
var items = [
  'item1',
  if (showItem) 'item2',    // Conditional
];
var doubled = [for (var i in [1,2,3]) i * 2]; // [2, 4, 6]

Map

// Map
var mahasiswa = {
  'nama': 'Budi',
  'nim': '2024001',
  'ipk': 3.75,
};

// Operasi Map
mahasiswa['semester'] = 5;
mahasiswa.remove('ipk');
mahasiswa.containsKey('nama');   // true
mahasiswa.containsValue('Budi'); // true
mahasiswa.keys;                  // (nama, nim, semester)
mahasiswa.values;                // (Budi, 2024001, 5)

// Iterasi
mahasiswa.forEach((key, value) {
  print('$key: $value');
});

// Map dari List
var angka = [1, 2, 3];
var mapAngka = angka.asMap(); // {0: 1, 1: 2, 2: 3}

5. Common Flutter Widgets

Layout Widgets

WidgetKeteranganContoh Penggunaan
ContainerBox dengan padding, margin, decorationWrapper serbaguna
RowSusun anak secara horizontalNavbar, button group
ColumnSusun anak secara vertikalForm, daftar item
StackSusun anak bertumpuk (z-axis)Overlay, badge
WrapSeperti Row tapi bisa wrap ke baris baruChip/tag
ListViewScrollable listDaftar item panjang
GridViewGrid scrollableGallery, katalog
ExpandedExpand anak di Row/ColumnFlex layout
FlexibleSeperti Expanded tapi bisa shrinkResponsive layout
SizedBoxBox dengan ukuran tetapSpacer, fixed size
PaddingTambahkan paddingSpacing konten
CenterCenter anakContent centering
AlignAlign anak ke posisi tertentuPositioning
ScaffoldStruktur halaman MaterialSetiap halaman utama
SafeAreaHindari notch/status barWrapper halaman

Input & Display Widgets

WidgetKeterangan
TextTampilkan teks
TextFieldInput teks
ElevatedButtonTombol dengan elevation
TextButtonTombol flat tanpa elevation
IconButtonTombol berupa ikon
ImageTampilkan gambar (asset/network/file)
IconTampilkan ikon Material
CardCard Material Design
ListTileList item Material
CircleAvatarBulat, untuk foto profil
ChipLabel kecil compact
CheckboxCheckbox input
SwitchToggle on/off
DropdownButtonDropdown selection
SliderInput range nilai
CircularProgressIndicatorLoading spinner
LinearProgressIndicatorLoading bar

6. StatelessWidget vs StatefulWidget

StatelessWidget

â„šī¸ Info

Gunakan StatelessWidget untuk widget yang tidak punya state internal — tampilannya hanya bergantung pada input (constructor) dan Theme.

class GreetingCard extends StatelessWidget {
  final String nama;

  const GreetingCard({super.key, required this.nama});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Text(
          'Halo, $nama!',
          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}

StatefulWidget

class CounterPage extends StatefulWidget {
  const CounterPage({super.key});

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: Center(
        child: Text('Count: $_count', style: TextStyle(fontSize: 32)),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _increment,
        child: Icon(Icons.add),
      ),
    );
  }
}

Perbandingan

AspekStatelessWidgetStatefulWidget
StateTidak ada state internalPunya state yang bisa berubah
RebuildHanya dari parentDari parent + setState()
Use caseTombol, label, card statisCounter, form, animation
PerformanceLebih ringanSedikit lebih berat
Lifecyclebuild() sajainitState, build, dispose, dll.

Navigator (Basic)

// Push halaman baru
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => DetailPage(id: 42)),
);

// Push dan ganti halaman (tidak bisa kembali)
Navigator.pushReplacement(
  context,
  MaterialPageRoute(builder: (context) => HomePage()),
);

// Push dan hapus semua stack
Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(builder: (context) => LoginPage()),
  (route) => false,
);

// Kembali ke halaman sebelumnya
Navigator.pop(context);

// Pop dengan result
Navigator.pop(context, 'result_data');

// Push dan dapatkan result
final result = await Navigator.push<String>(
  context,
  MaterialPageRoute(builder: (context) => SearchPage()),
);
print('Result: $result');

Named Routes

// Definisi routes di MaterialApp
MaterialApp(
  initialRoute: '/',
  routes: {
    '/': (context) => HomePage(),
    '/detail': (context) => DetailPage(),
    '/settings': (context) => SettingsPage(),
  },
);

// Navigasi dengan named route
Navigator.pushNamed(context, '/detail');
Navigator.pushNamed(context, '/detail', arguments: {'id': 42});

// Ambil arguments di halaman tujuan
final args = ModalRoute.of(context)!.settings.arguments as Map;

8. setState & State Lifecycle

StatefulWidget Lifecycle

MethodKapan Dipanggil
initState()Sekali saat widget dibuat (inisialisasi data)
didChangeDependencies()Setelah initState, atau saat InheritedWidget berubah
build()Setiap kali UI perlu di-rebuild
didUpdateWidget()Saat parent widget rebuild dengan widget baru
setState()Trigger rebuild (dipanggil manual)
deactivate()Saat widget dihapus dari tree sementara
dispose()Saat widget dihapus permanen (cleanup)
class TimerPage extends StatefulWidget {
  @override
  State<TimerPage> createState() => _TimerPageState();
}

class _TimerPageState extends State<TimerPage> {
  int _seconds = 0;
  late Timer _timer;

  @override
  void initState() {
    super.initState();
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() {
        _seconds++;
      });
    });
  }

  @override
  void dispose() {
    _timer.cancel(); // WAJIB cancel timer
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(child: Text('$_seconds detik'));
  }
}

9. Provider Basics

💡 Tips

Provider adalah state management yang direkomendasikan oleh tim Flutter. Alternatif lain: Riverpod, BLoC, GetX.

Setup

// pubspec.yaml
dependencies:
  provider: ^6.1.0

1. Buat ChangeNotifier

import 'package:flutter/foundation.dart';

class CartModel extends ChangeNotifier {
  final List<Map<String, dynamic>> _items = [];

  List<Map<String, dynamic>> get items => _items;
  int get itemCount => _items.length;
  double get totalPrice =>
      _items.fold(0, (sum, item) => sum + (item['price'] * item['qty']));

  void addItem(String name, double price) {
    _items.add({'name': name, 'price': price, 'qty': 1});
    notifyListeners(); // WAJIB untuk trigger rebuild
  }

  void removeItem(int index) {
    _items.removeAt(index);
    notifyListeners();
  }

  void clear() {
    _items.clear();
    notifyListeners();
  }
}

2. Provide di Root

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => CartModel()),
        ChangeNotifierProvider(create: (_) => AuthModel()),
      ],
      child: MyApp(),
    ),
  );
}

3. Konsumsi di Widget

// Consumer - rebuild hanya widget di dalam builder
Consumer<CartModel>(
  builder: (context, cart, child) {
    return Text('${cart.itemCount} item');
  },
)

// Provider.of - baca tanpa rebuild
final cart = Provider.of<CartModel>(context, listen: false);
cart.addItem('Kaos', 150000);

// context.read - sama dengan listen: false (sekali baca)
context.read<CartModel>().addItem('Kaos', 150000);

// context.watch - rebuild saat berubah
final count = context.watch<CartModel>().itemCount;

// Selector - rebuild hanya saat value tertentu berubah
Selector<CartModel, int>(
  selector: (_, cart) => cart.itemCount,
  builder: (_, count, __) => Text('$count items'),
)

10. HTTP Requests

Setup

// pubspec.yaml
dependencies:
  http: ^1.2.0

// Import
import 'package:http/http.dart' as http;
import 'dart:convert';

CRUD Operations

// GET - Ambil data
Future<List<dynamic>> getUsers() async {
  final response = await http.get(
    Uri.parse('https://api.example.com/users'),
    headers: {'Authorization': 'Bearer $token'},
  );

  if (response.statusCode == 200) {
    return jsonDecode(response.body);
  } else {
    throw Exception('Gagal memuat data: ${response.statusCode}');
  }
}

// POST - Kirim data
Future<Map<String, dynamic>> createUser(String nama, String email) async {
  final response = await http.post(
    Uri.parse('https://api.example.com/users'),
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer $token',
    },
    body: jsonEncode({
      'nama': nama,
      'email': email,
    }),
  );

  if (response.statusCode == 201) {
    return jsonDecode(response.body);
  } else {
    throw Exception('Gagal membuat user');
  }
}

// PUT - Update data
Future<void> updateUser(int id, Map<String, dynamic> data) async {
  final response = await http.put(
    Uri.parse('https://api.example.com/users/$id'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode(data),
  );

  if (response.statusCode != 200) {
    throw Exception('Gagal mengupdate user');
  }
}

// DELETE - Hapus data
Future<void> deleteUser(int id) async {
  final response = await http.delete(
    Uri.parse('https://api.example.com/users/$id'),
  );

  if (response.statusCode != 200) {
    throw Exception('Gagal menghapus user');
  }
}

11. JSON Parsing & Serialization

Manual Parsing

class User {
  final int id;
  final String nama;
  final String email;
  final String? avatar;

  User({
    required this.id,
    required this.nama,
    required this.email,
    this.avatar,
  });

  // Factory constructor dari JSON
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      nama: json['nama'] as String,
      email: json['email'] as String,
      avatar: json['avatar'] as String?,
    );
  }

  // Convert ke JSON
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'nama': nama,
      'email': email,
      'avatar': avatar,
    };
  }
}

// Menggunakan
void parseData() async {
  // Parse single object
  final response = await http.get(Uri.parse('https://api.example.com/users/1'));
  final jsonData = jsonDecode(response.body);
  final user = User.fromJson(jsonData);

  // Parse list
  final listResponse = await http.get(Uri.parse('https://api.example.com/users'));
  final List<dynamic> jsonList = jsonDecode(listResponse.body);
  final users = jsonList.map((json) => User.fromJson(json)).toList();

  // Convert ke JSON string
  final jsonString = jsonEncode(user.toJson());
  print(jsonString);
}

JSON Serializable (Code Generation)

// pubspec.yaml
dependencies:
  json_annotation: ^4.8.0
dev_dependencies:
  json_serializable: ^6.7.0
  build_runner: ^2.4.0

// user.dart
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';

@JsonSerializable()
class User {
  final int id;
  final String nama;
  @JsonKey(name: 'email_address') // Custom key mapping
  final String email;

  User({required this.id, required this.nama, required this.email});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

// Generate: dart run build_runner build

12. Flutter CLI Commands

PerintahKeterangan
flutter create myappBuat project baru
flutter create --org com.example myappBuat dengan org name
flutter runJalankan di device/emulator
flutter run -d chromeJalankan di Chrome
flutter run -d <device_id>Jalankan di device tertentu
flutter devicesList device yang terhubung
flutter pub getInstall dependencies
flutter pub add httpTambah package
flutter pub remove httpHapus package
flutter pub upgradeUpdate dependencies
flutter cleanBersihkan build cache
flutter build apkBuild APK (Android)
flutter build appbundleBuild AAB untuk Play Store
flutter build iosBuild iOS (macOS only)
flutter build webBuild untuk web
flutter testJalankan semua test
flutter analyzeAnalyze kode (linting)
flutter doctorCek setup environment
flutter doctor -vCek setup (verbose)
flutter upgradeUpgrade Flutter SDK
flutter gen-l10nGenerate localization
dart run build_runner buildGenerate code (json_serializable, dll)
dart run build_runner watchAuto-generate saat file berubah

13. Layout Tips & Patterns

Responsive Layout

// MediaQuery - dapatkan ukuran layar
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
bool isMobile = width < 600;
bool isTablet = width >= 600 && width < 1200;
bool isDesktop = width >= 1200;

// LayoutBuilder - responsive berdasarkan parent constraints
LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 600) {
      return _buildWideLayout();
    } else {
      return _buildNarrowLayout();
    }
  },
)

// OrientationBuilder
OrientationBuilder(
  builder: (context, orientation) {
    return orientation == Orientation.portrait
        ? _buildPortrait()
        : _buildLandscape();
  },
)

Common Layout Patterns

PatternWidgetKeterangan
Vertikal scrollSingleChildScrollViewWrap Column yang panjang
Horizontal scrollSingleChildScrollView(scrollDirection: Axis.horizontal)Tab bar, carousel
List besarListView.builderLazy loading, performa baik
Grid besarGridView.builderGrid dengan lazy loading
Sticky headerCustomScrollView + SliverAppBarCollapsing toolbar
Tab pagesTabBarView + TabControllerSwipeable tabs
Bottom sheetshowModalBottomSheet()Panel dari bawah
DialogshowDialog()Popup dialog
Snack barScaffoldMessenger.showSnackBar()Toast notification
← Sebelumnya Cheatsheet Docker & K8s Selanjutnya → Artikel Lainnya
🔍 Zoom
100%
🎨 Tema