Episode ini memasuki wilayah lanjutan: custom render objects dan widget di bawah permukaan, adaptasi spesifik platform dan aplikasi responsif, micro frontends dan plugin-driven architectures, serta hybrid app patterns dengan web dan desktop.

Kalian sudah nyaman di lapisan widget. Episode 18 turun lebih dalam dan menaikkan perspektif: memahami custom render objects untuk kontrol rendering total, beradaptasi dengan perbedaan platform, mengorganisasi aplikasi besar dengan arsitektur modular, dan membangun pola hybrid untuk web dan desktop.
Widget biasa mendeskripsikan konfigurasi; render object melakukan pekerjaan nyata — layout dan painting. Ketika kebutuhan layout tidak bisa dipenuhi widget bawaan, kalian menulis render object sendiri.
Render object biasanya diakses melalui SingleChildRenderObjectWidget, yang menciptakan dan meng-update render object:
class StretchWidget extends SingleChildRenderObjectWidget {
const StretchWidget({super.key, required super.child});
@override
RenderObject createRenderObject(BuildContext context) {
return _StretchRenderObject();
}
@override
void updateRenderObject(
BuildContext context,
covariant _StretchRenderObject renderObject,
) {}
}createRenderObject membangun render object; updateRenderObject menyinkronkan konfigurasi saat widget di-update. Kustomisasi layout kemudian hidup di class _StretchRenderObject yang meng-extend RenderBox.
Tulis render object hanya ketika widget composition tidak cukup: layout yang bergantung pada ukuran child secara tidak standar, atau performa yang tidak bisa dicapai lewat widget biasa. Untuk 99 persen kasus, kombinasi LayoutBuilder, CustomSingleChildLayout, dan CustomPaint sudah memadai — jangan optimasi berlebihan.
Aplikasi yang berjalan di ponsel, tablet, dan desktop butuh layout adaptif:
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth >= 900) {
return const WideLayout();
} else if (constraints.maxWidth >= 600) {
return const MediumLayout();
}
return const NarrowLayout();
},
)constraints.maxWidth menentukan lebar tersedia, lalu layout dipilih berdasarkan breakpoint. LayoutBuilder lebih responsif daripada MediaQuery karena mengikuti constraint widget, bukan ukuran layar penuh.
Untuk memenuhi kebiasaan tiap platform, sesuaikan pola navigasi:
if (constraints.maxWidth >= 900) {
return const NavigationRail(
selectedIndex: 0,
destinations: [
NavigationRailDestination(
icon: Icon(Icons.home),
label: Text('Beranda'),
),
],
);
}NavigationRail menggantikan BottomNavigationBar pada layar lebar — pola standar aplikasi desktop. Adaptasi kecil semacam ini membuat aplikasi terasa "asli" di setiap platform.
Untuk aplikasi enterprise, terapkan feature modules (dari episode 11) dengan aturan ketat: tiap modul memiliki antarmuka publik dan dependency injection yang jelas. Ini analog dengan microservices di sisi backend — setiap tim bisa bekerja di modulnya tanpa konflik.
Jadikan kemampuan ekstensibel lewat antarmuka:
abstract class PaymentProvider {
Future<PaymentResult> process(PaymentRequest request);
}
class MidtransProvider implements PaymentProvider {
@override
Future<PaymentResult> process(PaymentRequest request) async {
return PaymentResult(success: true);
}
}PaymentProvider adalah antarmuka, dan MidtransProvider salah satu implementasinya. Menambah gateway pembayaran baru tinggal menulis class baru tanpa mengubah alur inti — ini pattern strategy yang menjaga aplikasi besar tetap bisa tumbuh.
Flutter sudah menangani mobile, web, dan desktop dari satu codebase. Perbedaan target dikelola lewat:
universal_html untuk API browser di target web.-p saat flutter create.flutter create . --platforms=android,ios,web,linux,macos,windowsflutter create . --platforms=android,ios,web,linux,macos,windows menambahkan folder platform yang belum ada ke project yang sudah berjalan. Satu codebase sekarang mencakup seluruh target.
Pisahkan logika yang benar-benar berbeda per platform di direktori dengan suffix platform dan conditional import. Simpan perilaku yang bisa disatukan di satu tempat. Prinsipnya: satukan sebanyak mungkin, pisahkan hanya saat teknologi benar-benar berbeda.
Inti yang harus dibawa pulang:
SingleChildRenderObjectWidget.LayoutBuilder dengan breakpoint menghasilkan layout adaptif.NavigationRail untuk layar lebar.flutter create --platforms.Di episode 19 selanjutnya kita membahas operational readiness dan runbooks — runbook untuk app crashes dan release issues, monitoring stabilitas aplikasi dengan analytics dan error reporting, strategi rollout dan rollback, serta team workflows untuk maintenance. Aplikasi kalian siap dijaga di produksi.