CustomPainter — apa itu, metode paint dan shouldRepaint di Flutter

Penulis: IT Sectr Diterbitkan: 2026-07-22 Waktu membaca: 10 mnt

CustomPainter — adalah kelas abstrak dari Flutter SDK yang memberikan pengembang kendali penuh atas rendering grafis 2D kustom di Canvas. Pengembang membuat subkelas CustomPainter dan mengimplementasikan dua metode wajib: paint(Canvas, Size) dan shouldRepaint(covariant CustomPainter oldDelegate). Menurut Flutter API Documentation (2026), CustomPainter digunakan bersama dengan widget CustomPaint, yang mendelegasikan rendering ke objek CustomPainter yang diberikan pada setiap frame animasi atau perubahan status.

Poin Utama

  • CustomPainter — kelas abstrak Flutter yang mendefinisikan rendering kustom di Canvas melalui metode paint dan shouldRepaint
  • CustomPaint — widget yang menerima CustomPainter sebagai parameter painter atau foregroundPainter dan menampilkan hasilnya di layar
  • Canvas — objek yang menyediakan metode menggambar (drawLine, drawCircle, drawPath, drawRect, drawArc dan lainnya)
  • shouldRepaint — metode optimasi yang menentukan apakah objek perlu digambar ulang saat pembaruan
  • size — ukuran area gambar, yang diteruskan ke paint(Canvas canvas, Size size) dari widget induk

Apa itu CustomPainter?

CustomPainter — adalah kelas dasar Flutter untuk mengimplementasikan grafis 2D sembarang. Ini menggantikan pendekatan dengan menimpa onDraw di Android, memberikan model rendering yang lebih fleksibel dan deklaratif. Pengembang membuat subkelas CustomPainter, menimpa metode paint, di mana ia menerima Canvas dan Size, dan melakukan semua operasi menggambar di Canvas. Widget CustomPaint mengelola pemanggilan paint dan mengintegrasikan hasilnya ke dalam pohon widget.

Perbedaan utama antara CustomPainter dan menggambar langsung melalui Canvas — pemisahan logika rendering (paint) dan pemicu penggambaran ulang (shouldRepaint). Sistem Flutter memanggil shouldRepaint setiap kali widget induk berubah. Jika shouldRepaint mengembalikan false, paint tidak dipanggil, yang menghemat sumber daya. Mekanisme ini mirip dengan shouldRebuild di RenderObject dan merupakan bagian dari arsitektur Flutter dengan tiga pohonnya (Widget, Element, RenderObject).

CustomPaint — adalah widget yang menerima parameter painter (lapisan latar belakang) dan foregroundPainter (lapisan depan). Kedua parameter menerima objek CustomPainter. Painter latar belakang menggambar sebelum anak CustomPaint, dan foregroundPainter setelahnya. Ini memungkinkan penggunaan CustomPaint sebagai wadah dengan latar belakang dekoratif atau overlay, tanpa kehilangan kemampuan untuk menyematkan widget biasa di dalamnya.

Canvas dan Paint di Flutter

Canvas — adalah objek pusat untuk menggambar di Flutter, yang merangkum permukaan grafis. Ini menyediakan sekitar 40 metode menggambar: drawLine, drawCircle, drawRect, drawPath, drawArc, drawImage, drawPicture, drawPoints dan lainnya. Canvas di Flutter sesuai dengan kelas serupa di Android Canvas, tetapi disesuaikan dengan arsitektur Dart dan Flutter Engine. Canvas bekerja dalam sistem koordinat di mana titik asal (0, 0) adalah sudut kiri atas.

Paint — jangan disamakan dengan metode paint() — adalah kelas yang mendefinisikan gaya menggambar: warna (color), ketebalan garis (strokeWidth), gaya (style: fill atau stroke), transparansi, mode campuran (blendMode) dan masker anti-aliasing. Paint dikonfigurasi sebelum menggambar dan diteruskan ke metode Canvas. Penting: Paint adalah objek yang dapat diubah, tetapi disarankan untuk membuatnya sekali dan menggunakan kembali, hanya mengubah parameter yang diperlukan.

Metode CanvasTujuanParameter
drawCircleMenggambar lingkaranOffset center, double radius, Paint paint
drawLineMenggambar garisOffset p1, Offset p2, Paint paint
drawRectMenggambar persegi panjangRect rect, Paint paint
drawPathMenggambar kontur sembarangPath path, Paint paint
drawArcMenggambar busur atau sektorRect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint
drawRRectPersegi panjang dengan sudut membulatRRect rrect, Paint paint
drawOvalMenggambar ovalRect rect, Paint paint
drawImageMenggambar gambar dari ImageImage image, Offset p, Paint paint

Transformasi Canvas

Canvas mendukung transformasi sistem koordinat: translate(double dx, double dy) memindahkan titik asal koordinat; rotate(double radians) memutar sistem; scale(double sx, double sy) menskala; skew(double sx, double sy) memiringkan. Sebelum transformasi disarankan untuk menyimpan status Canvas melalui save(), dan setelah selesai mengembalikannya melalui restore(). Ini mencegah akumulasi transformasi pada pemanggilan paint berikutnya.

Metode paint dan shouldRepaint

paint(Canvas canvas, Size size) — metode wajib di mana seluruh logika menggambar diimplementasikan. Parameter canvas — permukaan grafis untuk menggambar. Parameter size — ukuran area yang dialokasikan untuk menggambar (lebar dan tinggi dalam piksel logis). Canvas telah dikonfigurasi sebelumnya sehingga titik asal koordinat (0,0) sesuai dengan sudut kiri atas area gambar. Semua koordinat ditentukan relatif terhadap titik asal ini.

shouldRepaint(covariant CustomPainter oldDelegate) — metode wajib yang mengoptimalkan frekuensi penggambaran ulang. Flutter memanggil shouldRepaint setiap kali pohon widget diperbarui yang mempengaruhi CustomPainter. Jika metode mengembalikan false, gambar yang sudah digambar dianggap valid dan paint tidak dipanggil. Implementasi tipikal: return oldDelegate.someField != someField — perbandingan bidang painter lama dan baru untuk menentukan kebutuhan penggambaran ulang.

Untuk gambar beranimasi atau terus berubah (jam, indikator pemuatan, grafik) shouldRepaint harus mengembalikan true pada setiap perubahan status. Jika objek statis (logo, ikon, latar belakang), shouldRepaint mengembalikan false setelah rendering pertama. Flutter secara otomatis menyimpan cache hasil paint dan menggambar ulang hanya saat ukuran, transparansi berubah, atau shouldRepaint dipanggil.

Contoh menggambar kustom dengan CustomPainter di Dart

Mari buat GaugePainter — indikator melingkar kustom dengan isian beranimasi. CustomPainter menerima nilai saat ini (progress dari 0.0 hingga 1.0) dan menggambar busur dengan gradien. Dalam metode shouldRepaint, nilai progress dibandingkan untuk optimasi. CustomPaint ditempatkan di pohon widget dengan parameter size untuk membatasi area gambar.

dart
class GaugePainter extends CustomPainter {
    final double progress;
    final Color startColor;
    final Color endColor;

    GaugePainter({
        required this.progress,
        this.startColor = Colors.blue,
        this.endColor = Colors.cyan,
    });

    @override
    void paint(Canvas canvas, Size size) {
        final center = Offset(size.width / 2,
            size.height / 2);
        final radius = center.dx - 12;
        final bgPaint = Paint()
            ..color = Colors.grey.withOpacity(0.3)
            ..style = PaintingStyle.stroke
            ..strokeWidth = 16
            ..strokeCap = StrokeCap.round;

        final progressPaint = Paint()
            ..shader = LinearGradient(
                colors: [startColor, endColor],
            ).createShader(
                Rect.fromCircle(
                    center, radius))
            ..style = PaintingStyle.stroke
            ..strokeWidth = 16
            ..strokeCap = StrokeCap.round;

        canvas.drawCircle(center, radius, bgPaint);
        canvas.drawArc(
            Rect.fromCircle(center, radius),
            -math.pi / 2,
            2 * math.pi * progress,
            false, progressPaint);
    }

    @override
    bool shouldRepaint(
        GaugePainter oldDelegate) {
        return oldDelegate.progress != progress;
    }
}

CustomPainter dengan Path untuk bentuk kompleks

Contoh menggambar grafik gelombang menggunakan Path. Path memungkinkan membangun kontur sembarang dari garis, kurva Bezier, dan busur. Setelah dibangun, kontur diisi dengan warna atau digaris dengan garis. Dalam contoh, grafik dibangun berdasarkan array titik yang meniru bentuk gelombang.

dart
class WavePainter extends CustomPainter {
    final List<double> values;

    WavePainter({required this.values});

    @override
    void paint(Canvas canvas, Size size) {
        final path = Path();
        final dx = size.width /
            (values.length - 1);

        path.moveTo(0, size.height);
        for (var i = 0; i < values.length; i++) {
            final x = i * dx;
            final y = size.height *
                (1 - values[i]);
            path.lineTo(x, y);
        }
        path.lineTo(size.width, size.height);
        path.close();

        final fillPaint = Paint()
            ..color = Colors.blue.withOpacity(0.3)
            ..style = PaintingStyle.fill;

        canvas.drawPath(path, fillPaint);
    }

    @override
    bool shouldRepaint(
        WavePainter oldDelegate) {
        return oldDelegate.values != values;
    }
}

ForegroundPainter dan backgroundPainter: perbedaan

painter (latar belakang) menggambar sebelum anak CustomPaint. Jika CustomPaint memiliki anak (parameter child), painter latar belakang ditampilkan di bawahnya. Ini cocok untuk dekorasi: bilah kemajuan, pola latar belakang, tanda air. foregroundPainter menggambar setelah anak CustomPaint, yaitu di atasnya. Digunakan untuk overlay: sorotan, topeng, penggaris ukur, anotasi.

Perbedaan antara painter dan foregroundPainter sangat penting untuk Z-order. Jika perlu menggambar sesuatu di belakang konten — gunakan painter. Jika di atas konten — foregroundPainter. Dalam beberapa kasus, Anda dapat menggunakan kedua painter secara bersamaan: latar belakang melalui painter, label-overlay melalui foregroundPainter. Ini memungkinkan pemisahan logika lapisan grafis yang berbeda menjadi dua kelas CustomPainter terpisah.

Parameter size dalam metode paint sama untuk kedua painter dan ditentukan oleh ukuran area yang dialokasikan untuk CustomPaint. Ukuran dapat diatur secara eksplisit melalui parameter size di CustomPaint atau secara implisit melalui wadah induk. Jika size sama dengan Size.zero, paint tidak dipanggil — Flutter melewatkan rendering untuk area nol. Perilaku ini harus dipertimbangkan saat elemen muncul secara beranimasi.

Optimasi kinerja CustomPainter

Aturan utama kinerja CustomPainter — jangan membuat objek di dalam metode paint. Canvas, Paint, Path, Rect, Offset dan objek gambar lainnya harus dibuat di konstruktor CustomPainter atau di-cache. Membuat objek di dalam paint menyebabkan alokasi memori pada setiap frame, yang pada 60 frame per detik menyebabkan pengumpulan sampah yang sering dan animasi tersendat (jank).

Cache Path secara signifikan mempercepat rendering kontur kompleks yang berulang. Jika kontur tidak berubah antar frame (misalnya, kisi latar belakang), buat Path sekali dan gunakan berulang kali. RepaintBoundary — widget pembungkus yang mencegah penggambaran ulang CustomPainter saat pohon widget di atasnya berubah. Jika CustomPainter statis, bungkus dalam RepaintBoundary untuk isolasi.

Untuk CustomPainter beranimasi dengan penggambaran ulang yang sering, gunakan Ticker atau AnimationController dengan shouldRepaint yang mengembalikan true saat nilai animasi berubah. Optimal untuk membandingkan bidang animasi di shouldRepaint, bukan menggambar ulang pada setiap frame tanpa perlu. Cache Rect untuk gradien kompleks: jika gradien tidak mengubah warna, Anda dapat menyimpan cache Shader melalui Paint.shader.

Pertanyaan yang Sering Diajukan

Apa perbedaan antara CustomPainter dan Canvas di Flutter?

CustomPainter — adalah kelas kontrak yang menentukan apa dan bagaimana menggambar di Canvas. Canvas — adalah objek gambar itu sendiri yang menyediakan metode (drawCircle, drawLine dll.). CustomPainter menerima Canvas melalui metode paint dan mengelola penggunaannya. Satu Canvas dapat digunakan oleh CustomPainter yang berbeda pada waktu yang berbeda.

Bisakah CustomPainter digunakan tanpa CustomPaint?

Tidak, CustomPainter tidak berguna tanpa CustomPaint. CustomPaint adalah widget yang memanggil metode paint CustomPainter dan menampilkan hasilnya di layar. Tanpa CustomPaint, Canvas tidak akan dibuat dan paint tidak akan dijalankan. Namun, Anda dapat mengimplementasikan RenderObject sendiri dengan Canvas, tetapi ini adalah pendekatan tingkat yang lebih rendah.

Bagaimana cara menganimasikan CustomPainter?

Gunakan AnimationController dengan Ticker, teruskan nilai animasi ke CustomPainter melalui parameter konstruktor. Saat nilai berubah, panggil setState() di widget yang berisi CustomPaint, yang memicu shouldRepaint. Jika shouldRepaint mengembalikan true, sistem memanggil paint untuk frame animasi baru.

Mengapa CustomPainter tidak diperbarui saat data berubah?

Penyebabnya hampir selalu shouldRepaint yang mengembalikan false. Periksa apakah bidang oldDelegate dibandingkan dengan benar dengan nilai baru. Jika menggunakan objek yang dapat diubah, shouldRepaint mungkin tidak melihat perubahan karena referensi ke objek tetap sama. Gunakan == atau objek yang tidak dapat diubah untuk perbandingan yang benar.

Bisakah CustomPainter digunakan untuk animasi di ReorderableListView?

Ya, CustomPainter digunakan untuk menggambar dekorasi kustom di daftar kompleks. Namun, perlu diingat bahwa saat mengurutkan ulang elemen, RepaintBoundary di dalam ListView menyimpan cache rendering setiap elemen. CustomPainter harus ringan dan tidak mengandung operasi berat di paint agar tidak memperlambat animasi seret.

Ringkasan

  • CustomPainter — kelas abstrak Flutter untuk rendering 2D kustom dengan metode paint dan shouldRepaint
  • CustomPaint — widget yang menerima painter (latar belakang) dan foregroundPainter (latar depan) untuk menampilkan grafis
  • Canvas — objek dengan metode menggambar: drawLine, drawCircle, drawPath, drawRect, drawArc dan lainnya
  • Paint — kelas yang mendefinisikan gaya menggambar: warna, ketebalan, gaya (fill/stroke), transparansi dan mode campuran
  • shouldRepaint — metode optimasi yang mengembalikan true hanya saat bidang yang mempengaruhi rendering berubah
  • Membuat objek di dalam paint dilarang — semua Paint, Path, Rect harus di-cache untuk 60 fps
  • RepaintBoundary — widget untuk mengisolasi CustomPainter dari penggambaran ulang pohon widget di atasnya

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga