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 key
  • FlutterError dan ErrorWidget — penanganan error di framework
  • kDebugMode, kProfileMode, kReleaseMode — flag untuk membedakan mode build
  • LicenseRegistry — 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 + Curve yang 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, dan InheritedWidget — 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 →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact