Framework Layer #
Framework Layer adalah lapisan yang paling sering kamu sentuh setiap hari sebagai Flutter developer. Seluruhnya ditulis dalam Dart, bersifat open-source, dan dapat kamu baca langsung source code-nya. Artikel ini membahas setiap sub-lapisan Framework secara mendalam — dari Foundation di bawah hingga Material/Cupertino di atas.
Struktur Framework Layer #
Framework Layer terdiri dari beberapa sub-lapisan yang disusun dari bawah ke atas. Semakin ke bawah, semakin dekat ke Engine dan semakin banyak kendali yang kamu miliki. Semakin ke atas, semakin abstrak dan mudah digunakan.
+------------------------------------------+
| Material / Cupertino | <-- Paling mudah digunakan
+------------------------------------------+
| Widgets |
+------------------------------------------+
| Rendering |
+------------------------------------------+
| Animation | Painting | Gestures |
+------------------------------------------+
| Foundation (dart:ui wrapper) | <-- Paling dekat ke Engine
+------------------------------------------+
| Flutter Engine (C++) |
+------------------------------------------+
Prinsip utamanya: lapisan yang lebih tinggi dibangun di atas lapisan yang lebih rendah. Kamu bebas menggunakan lapisan manapun secara langsung — tidak harus selalu melalui lapisan teratas.
Foundation #
Foundation adalah sub-lapisan paling bawah dalam Framework. Ia menjadi jembatan antara Flutter Engine (melalui dart:ui) dan lapisan Framework di atasnya.
Apa yang Ada di Foundation? #
import 'package:flutter/foundation.dart';
// ChangeNotifier — mekanisme notifikasi perubahan state
class Counter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // beritahu semua listener bahwa state berubah
}
}
// ValueNotifier — versi sederhana ChangeNotifier untuk satu nilai
final ValueNotifier<int> counter = ValueNotifier<int>(0);
counter.addListener(() => print('Nilai baru: ${counter.value}'));
counter.value = 42; // otomatis trigger listener
// Diagnosticable — untuk debugging dan Flutter Inspector
class MyWidget extends Widget with DiagnosticableTreeMixin {
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(StringProperty('nama', 'MyWidget'));
}
}
Foundation juga menyediakan:
Key— identifier unik untuk widget (dibahas lebih detail di artikel Widget)UniqueKey,ValueKey,ObjectKey,GlobalKey— berbagai jenis keyFlutterErrordanErrorWidget— penanganan error di frameworkkDebugMode,kProfileMode,kReleaseMode— flag untuk membedakan mode buildLicenseRegistry— registrasi lisensi package untuk tampilan About dialog
// Contoh penggunaan flag mode build
void initApp() {
if (kDebugMode) {
print('Berjalan dalam mode debug');
}
if (kReleaseMode) {
// Inisialisasi analytics, crash reporting, dll.
Crashlytics.instance.setCrashlyticsCollectionEnabled(true);
}
}
Animation #
Sub-lapisan Animation menyediakan sistem animasi yang kaya dan fleksibel. Flutter tidak bergantung pada animasi CSS atau animasi bawaan platform — semua diatur melalui sistem animasi Dart yang berjalan di UI thread.
Konsep Inti Animation #
Animation<T> adalah abstraksi nilai yang berubah seiring waktu. Nilainya bisa berupa double, Color, Offset, atau tipe apapun.
AnimationController adalah sumber “detak jantung” animasi — mengontrol durasi dan arah animasi:
class _MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
// AnimationController: sumber waktu animasi
_controller = AnimationController(
vsync: this, // sinkronisasi dengan frame rate layar
duration: const Duration(milliseconds: 500),
);
// Tween mendefinisikan rentang nilai
_fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut, // kurva animasi
));
_slideAnimation = Tween<Offset>(
begin: const Offset(0, 0.3),
end: Offset.zero,
).animate(_controller);
}
@override
void dispose() {
_controller.dispose(); // selalu dispose controller!
super.dispose();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: const Text('Animasi masuk!'),
),
);
}
}
Jenis-jenis Curve #
Flutter menyediakan puluhan kurva animasi bawaan:
// Kurva yang tersedia di Curves class:
Curves.linear // konstan, tidak ada akselerasi
Curves.easeIn // mulai lambat, makin cepat
Curves.easeOut // mulai cepat, melambat di akhir
Curves.easeInOut // lambat di awal dan akhir
Curves.bounceOut // efek pantulan di akhir
Curves.elasticOut // efek pegas di akhir
Curves.decelerate // melambat secara smooth
Painting #
Sub-lapisan Painting menyediakan abstraksi untuk menggambar ke canvas — membungkus API dart:ui yang lebih rendah menjadi API yang lebih nyaman digunakan.
CustomPainter #
CustomPainter adalah cara paling langsung untuk menggambar grafis kustom di Flutter:
class GrafikBatang extends CustomPainter {
final List<double> data;
GrafikBatang(this.data);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
final lebarBatang = size.width / data.length;
for (int i = 0; i < data.length; i++) {
final tinggi = data[i] * size.height;
final rect = Rect.fromLTWH(
i * lebarBatang + 4, // x dengan sedikit padding
size.height - tinggi, // y (dari atas)
lebarBatang - 8, // lebar
tinggi, // tinggi
);
canvas.drawRect(rect, paint);
}
// Gambar garis sumbu X
final axisPaint = Paint()
..color = Colors.black
..strokeWidth = 2;
canvas.drawLine(
Offset(0, size.height),
Offset(size.width, size.height),
axisPaint,
);
}
@override
bool shouldRepaint(GrafikBatang oldDelegate) =>
oldDelegate.data != data; // hanya repaint jika data berubah
}
// Penggunaan di widget tree
CustomPaint(
size: const Size(300, 200),
painter: GrafikBatang([0.4, 0.7, 0.5, 0.9, 0.3]),
)
API Painting yang Tersedia #
// Menggambar berbagai bentuk
canvas.drawRect(rect, paint);
canvas.drawCircle(center, radius, paint);
canvas.drawLine(p1, p2, paint);
canvas.drawPath(path, paint);
canvas.drawImage(image, offset, paint);
canvas.drawRRect(roundedRect, paint); // rounded rectangle
// Transformasi canvas
canvas.save();
canvas.translate(dx, dy);
canvas.rotate(angle);
canvas.scale(sx, sy);
canvas.restore();
// Clipping
canvas.clipRect(rect);
canvas.clipPath(path);
Gestures #
Sub-lapisan Gestures menangani deteksi dan pengelolaan input sentuhan dari pengguna. Flutter memiliki sistem gesture yang sangat fleksibel dan dapat dikustomisasi.
GestureDetector #
Widget paling umum untuk mendeteksi gesture:
GestureDetector(
// Gesture sederhana
onTap: () => print('Tap!'),
onDoubleTap: () => print('Double tap!'),
onLongPress: () => print('Long press!'),
// Gesture drag
onPanStart: (details) => print('Mulai drag'),
onPanUpdate: (details) {
// details.delta berisi perubahan posisi
print('Delta: ${details.delta}');
},
onPanEnd: (details) => print('Selesai drag'),
// Gesture scale/pinch
onScaleStart: (details) => print('Mulai scale'),
onScaleUpdate: (details) {
print('Scale: ${details.scale}');
print('Rotasi: ${details.rotation}');
},
child: Container(
width: 200,
height: 200,
color: Colors.blue,
child: const Center(child: Text('Sentuh saya!')),
),
)
Gesture Arena #
Flutter menggunakan sistem Gesture Arena untuk menyelesaikan konflik antara beberapa gesture yang bersaing secara bersamaan — misalnya ketika onTap dan onLongPress perlu bersaing:
Pengguna menyentuh layar
|
v
Semua GestureRecognizer yang aktif
masuk ke dalam "arena"
|
v
Setiap recognizer mengamati event
|
+---------+
| |
Menang Kalah
| |
v v
Dipanggil Diabaikan
Ketika jari diam terlalu lama → onLongPress menang, onTap diabaikan. Ketika jari diangkat cepat → onTap menang, onLongPress diabaikan.
Rendering #
Sub-lapisan Rendering adalah “otak” layout Flutter. Di sinilah RenderObject menghitung ukuran, posisi, dan menggambar widget ke canvas.
Constraint-Based Layout #
Flutter menggunakan sistem layout berbasis constraint. Prinsipnya terkenal dengan singkatan:
"Constraints go down, sizes go up, parent sets position"
Parent --> [constraint: maxW=360, maxH=800] --> Child
Child --> [size: width=200, height=50] --> Parent
Parent --> menetapkan posisi child di (80, 100)
RenderBox — Implementasi Paling Umum #
RenderBox adalah implementasi RenderObject yang menggunakan model layout kotak (box model):
// Membuat RenderObject kustom (jarang diperlukan, tapi penting dipahami)
class RenderLingkaran extends RenderBox {
Color warna;
RenderLingkaran({required this.warna});
@override
void performLayout() {
// Tentukan ukuran berdasarkan constraint dari parent
final sisi = constraints.biggest.shortestSide;
size = Size(sisi, sisi);
}
@override
void paint(PaintingContext context, Offset offset) {
final paint = Paint()..color = warna;
context.canvas.drawCircle(
offset + Offset(size.width / 2, size.height / 2),
size.width / 2,
paint,
);
}
}
RepaintBoundary — Optimasi Rendering #
RepaintBoundary adalah widget penting untuk optimasi performa — ia mencegah bagian widget tree yang tidak berubah untuk di-repaint:
// Tanpa RepaintBoundary: seluruh halaman di-repaint saat animasi berjalan
Column(
children: [
AnimatedWidget(), // berubah 60x/detik
StatisWidget(), // tidak pernah berubah — tapi ikut di-repaint!
],
)
// Dengan RepaintBoundary: hanya AnimatedWidget yang di-repaint
Column(
children: [
AnimatedWidget(),
RepaintBoundary( // buat boundary paint tersendiri
child: StatisWidget(),
),
],
)
Widgets #
Sub-lapisan Widgets membangun di atas Rendering dan menyediakan API yang jauh lebih nyaman: StatelessWidget, StatefulWidget, InheritedWidget, dan sistem BuildContext.
StatelessWidget vs StatefulWidget #
// StatelessWidget: UI yang tidak bergantung pada state internal
class SapaanWidget extends StatelessWidget {
final String nama;
const SapaanWidget({super.key, required this.nama});
@override
Widget build(BuildContext context) {
return Text('Halo, $nama!');
}
}
// StatefulWidget: UI yang memiliki state internal yang bisa berubah
class KonterWidget extends StatefulWidget {
const KonterWidget({super.key});
@override
State<KonterWidget> createState() => _KonterWidgetState();
}
class _KonterWidgetState extends State<KonterWidget> {
int _nilai = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Nilai: $_nilai'),
ElevatedButton(
onPressed: () => setState(() => _nilai++),
child: const Text('Tambah'),
),
],
);
}
}
InheritedWidget — State Sharing Bawaan Flutter #
InheritedWidget adalah mekanisme bawaan Flutter untuk berbagi data ke seluruh widget tree tanpa harus meneruskan data secara manual dari parent ke child:
// Mendefinisikan InheritedWidget
class TemaApp extends InheritedWidget {
final Color warnaUtama;
final double ukuranFont;
const TemaApp({
super.key,
required this.warnaUtama,
required this.ukuranFont,
required super.child,
});
// Cara mengakses dari descendant widget
static TemaApp of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<TemaApp>()!;
}
@override
bool updateShouldNotify(TemaApp oldWidget) {
// Kapan descendant perlu di-rebuild?
return oldWidget.warnaUtama != warnaUtama ||
oldWidget.ukuranFont != ukuranFont;
}
}
// Penggunaan di descendant widget mana pun
class TombolKustom extends StatelessWidget {
@override
Widget build(BuildContext context) {
final tema = TemaApp.of(context); // akses tanpa prop drilling!
return ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: tema.warnaUtama),
onPressed: () {},
child: Text('Klik', style: TextStyle(fontSize: tema.ukuranFont)),
);
}
}
Provider, Riverpod, dan BLoC semuanya dibangun di atas InheritedWidget. Memahami InheritedWidget berarti kamu memahami fondasi dari semua solusi state management Flutter yang populer.
Material & Cupertino #
Sub-lapisan paling atas Framework — mengimplementasikan dua design language lengkap menggunakan komposisi widget di lapisan bawahnya.
Material Library #
Material Library mengimplementasikan Material Design 3 (Material You) dari Google:
import 'package:flutter/material.dart';
MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
brightness: Brightness.light,
),
),
home: Scaffold(
appBar: AppBar(
title: const Text('Material 3'),
actions: [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {},
),
],
),
body: ListView(
children: [
Card(
child: ListTile(
leading: const CircleAvatar(child: Text('A')),
title: const Text('Item pertama'),
subtitle: const Text('Subjudul item'),
trailing: const Icon(Icons.chevron_right),
onTap: () {},
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
),
)
Cupertino Library #
Cupertino Library mengimplementasikan tampilan dan perilaku iOS native:
import 'package:flutter/cupertino.dart';
CupertinoApp(
theme: const CupertinoThemeData(
primaryColor: CupertinoColors.systemBlue,
),
home: CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text('Cupertino'),
),
child: SafeArea(
child: CupertinoListSection.insetGrouped(
children: [
CupertinoListTile(
title: const Text('Notifikasi'),
trailing: CupertinoSwitch(
value: true,
onChanged: (val) {},
),
),
CupertinoListTile(
title: const Text('Mode Gelap'),
trailing: const CupertinoListTileChevron(),
onTap: () {},
),
],
),
),
),
)
Ringkasan #
- Framework Layer terdiri dari 7 sub-lapisan dari bawah ke atas: Foundation → Animation → Painting → Gestures → Rendering → Widgets → Material/Cupertino.
- Foundation menyediakan utilitas dasar seperti
ChangeNotifier,ValueNotifier,Key, dan flag mode build.- Animation menggunakan sistem
AnimationController+Tween+Curveyang terpisah dari sistem animasi platform.- Gestures menggunakan Gesture Arena untuk menyelesaikan konflik antara gesture yang bersaing.
- Rendering menggunakan sistem layout berbasis constraint: “constraints go down, sizes go up, parent sets position.”
- Widgets menyediakan
StatelessWidget,StatefulWidget, danInheritedWidget— fondasi semua state management Flutter.- Material dan Cupertino mengimplementasikan dua design language lengkap — semuanya dibangun dari komposisi widget di lapisan bawah.
← Sebelumnya: Architecture Overview Berikutnya: Engine Layer →