CustomPainter — ano ito, mga pamamaraan ng paint at shouldRepaint sa Flutter

May-akda: IT Sectr Nai-publish: 2026-07-22 Oras ng pagbabasa: 10 min

CustomPainter — ay isang abstract na klase mula sa Flutter SDK na nagbibigay sa mga developer ng buong kontrol sa pag-render ng custom na 2D graphics sa Canvas. Gumagawa ang developer ng subclass ng CustomPainter at nagpapatupad ng dalawang mandatoryong pamamaraan: paint(Canvas, Size) at shouldRepaint(covariant CustomPainter oldDelegate). Ayon sa Flutter API Documentation (2026), ang CustomPainter ay ginagamit kasama ng widget na CustomPaint, na nagdedelegate ng pag-render sa ibinigay na object ng CustomPainter sa bawat frame ng animation o pagbabago ng estado.

Mga Pangunahing Punto

  • CustomPainter — abstract na klase ng Flutter na tumutukoy sa custom na pag-render sa Canvas sa pamamagitan ng mga pamamaraan ng paint at shouldRepaint
  • CustomPaint — widget na tumatanggap ng CustomPainter bilang parameter na painter o foregroundPainter at nagpapakita ng resulta sa screen
  • Canvas — object na nagbibigay ng mga pamamaraan ng pagguhit (drawLine, drawCircle, drawPath, drawRect, drawArc at iba pa)
  • shouldRepaint — pamamaraan ng optimisasyon na tumutukoy kung kailangan muling iguhit ang object sa pag-update
  • size — sukat ng lugar ng pagguhit, na ipinapasa sa paint(Canvas canvas, Size size) mula sa parent widget

Ano ang CustomPainter?

CustomPainter — ay pangunahing klase ng Flutter para sa pagpapatupad ng arbitraryong 2D graphics. Pinapalitan nito ang approach ng pag-override sa onDraw sa Android, na nagbibigay ng mas flexible at deklaratibong modelo ng pag-render. Gumagawa ang developer ng subclass ng CustomPainter, ni-ooverride ang pamamaraan ng paint, kung saan natatanggap nito ang Canvas at Size, at isinasagawa ang lahat ng operasyon ng pagguhit sa Canvas. Pinamamahalaan ng widget na CustomPaint ang pagtawag sa paint at isinasama ang resulta sa puno ng widget.

Ang pangunahing pagkakaiba sa pagitan ng CustomPainter at direktang pagguhit sa pamamagitan ng Canvas — ang paghihiwalay ng lohika ng pag-render (paint) at trigger ng muling pagguhit (shouldRepaint). Tinatawag ng Flutter system ang shouldRepaint sa bawat pagkakataon na nagbabago ang parent widget. Kung ang shouldRepaint ay nagbalik ng false, hindi tinatawag ang paint, na nakakatipid ng mga resources. Ang mekanismong ito ay kahalintulad ng shouldRebuild sa RenderObject at bahagi ng arkitektura ng Flutter na may tatlong puno nito (Widget, Element, RenderObject).

CustomPaint — ay isang widget na tumatanggap ng mga parameter na painter (layer ng background) at foregroundPainter (layer sa harap). Ang parehong parameter ay tumatanggap ng mga object ng CustomPainter. Ang painter ng background ay gumuhit bago ang anak ng CustomPaint, at ang foregroundPainter pagkatapos nito. Ito ay nagpapahintulot sa paggamit ng CustomPaint bilang isang container na may dekoratibong background o overlay, nang hindi nawawala ang kakayahang mag-embed ng mga ordinaryong widget sa loob.

Canvas at Paint sa Flutter

Canvas — ay sentral na object para sa pagguhit sa Flutter, na nag-encapsulate ng graphical na surface. Nagbibigay ito ng humigit-kumulang 40 pamamaraan ng pagguhit: drawLine, drawCircle, drawRect, drawPath, drawArc, drawImage, drawPicture, drawPoints at iba pa. Ang Canvas sa Flutter ay tumutugma sa kahalintulad na klase sa Android Canvas, ngunit inangkop sa arkitektura ng Dart at Flutter Engine. Gumagana ang Canvas sa isang coordinate system kung saan ang origin (0, 0) ay nasa kaliwang sulok sa itaas.

Paint — huwag ipagkamali sa pamamaraan ng paint() — ay isang klase na tumutukoy sa estilo ng pagguhit: kulay (color), kapal ng linya (strokeWidth), estilo (style: fill o stroke), transparency, blending mode (blendMode) at anti-aliasing mask. Paint ay kino-configure bago gumuhit at ipinapasa sa mga pamamaraan ng Canvas. Mahalaga: Ang Paint ay isang nababagong object, ngunit inirerekomenda na gawin ito nang isang beses at muling gamitin, baguhin lamang ang mga kinakailangang parameter.

Pamamaraan ng CanvasLayuninMga Parameter
drawCirclePagguhit ng bilogOffset center, double radius, Paint paint
drawLinePagguhit ng linyaOffset p1, Offset p2, Paint paint
drawRectPagguhit ng parihabaRect rect, Paint paint
drawPathPagguhit ng arbitraryong contourPath path, Paint paint
drawArcPagguhit ng arko o sektorRect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint
drawRRectParihaba na may bilugang sulokRRect rrect, Paint paint
drawOvalPagguhit ng obaloRect rect, Paint paint
drawImagePagguhit ng imahe mula sa ImageImage image, Offset p, Paint paint

Mga Transformasyon ng Canvas

Canvas ay sumusuporta sa mga transformasyon ng coordinate system: translate(double dx, double dy) inililipat ang origin ng coordinates; rotate(double radians) pinaiikot ang system; scale(double sx, double sy) pinalalaki o pinapaliit; skew(double sx, double sy) pinaiikit. Bago ang transformasyon ay inirerekomenda na i-save ang estado ng Canvas sa pamamagitan ng save(), at pagkatapos ng pagkumpleto ay ibalik ito sa pamamagitan ng restore(). Ito ay pumipigil sa akumulasyon ng mga transformasyon sa mga susunod na pagtawag ng paint.

Mga pamamaraan ng paint at shouldRepaint

paint(Canvas canvas, Size size) — ang mandatoryong pamamaraan kung saan ipinapatupad ang buong lohika ng pagguhit. Parameter canvas — ang graphical na surface para sa pagguhit. Parameter size — ang sukat ng lugar na inilaan para sa pagguhit (lapad at taas sa logical pixels). Ang Canvas ay naka-configure nang maaga upang ang origin ng coordinates (0,0) ay tumutugma sa kaliwang sulok sa itaas ng lugar ng pagguhit. Lahat ng coordinates ay itinakda kaugnay sa origin na ito.

shouldRepaint(covariant CustomPainter oldDelegate) — ang mandatoryong pamamaraan na nag-o-optimize sa dalas ng muling pagguhit. Tinatawag ng Flutter ang shouldRepaint sa bawat pag-update ng puno ng widget na nakakaapekto sa CustomPainter. Kung ang pamamaraan ay nagbalik ng false, ang iginuhit na larawan ay itinuturing na valid at hindi tinatawag ang paint. Karaniwang implementasyon: return oldDelegate.someField != someField — paghahambing ng mga field ng luma at bagong painter upang matukoy ang pangangailangan para sa muling pagguhit.

Para sa mga na-animate o patuloy na nagbabagong larawan (mga orasan, indicator ng pag-load, mga graph) ang shouldRepaint ay dapat magbalik ng true sa bawat pagbabago ng estado. Kung ang object ay static (logo, icon, background), ang shouldRepaint ay nagbabalik ng false pagkatapos ng unang pag-render. Awtomatikong ni-ca-cache ng Flutter ang resulta ng paint at muling gumuhit lamang kapag nagbago ang laki, transparency, o tinawag ang shouldRepaint.

Halimbawa ng custom na pagguhit gamit ang CustomPainter sa Dart

Gumawa tayo ng GaugePainter — isang custom na pabilog na indicator na may animated na pagpuno. Tumatanggap ang CustomPainter ng kasalukuyang halaga (progress mula 0.0 hanggang 1.0) at gumuhit ng arko na may gradient. Sa pamamaraan ng shouldRepaint, ang halaga ng progress ay inihahambing para sa optimisasyon. Ang CustomPaint ay inilalagay sa puno ng widget na may parameter na size upang limitahan ang lugar ng pagguhit.

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 na may Path para sa mga kumplikadong hugis

Ang halimbawa ay gumuhit ng wave graph gamit ang Path. Pinapayagan ng Path ang pagbuo ng mga arbitraryong contour mula sa mga linya, Bezier curves at arko. Pagkatapos ng pagbuo, ang contour ay pupunuan ng kulay o lalagyan ng linya. Sa halimbawa, ang graph ay binuo batay sa array ng mga puntos na ginagaya ang hugis ng alon.

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 at backgroundPainter: pagkakaiba

painter (background) ay gumuhit bago ang anak ng CustomPaint. Kung ang CustomPaint ay may anak (parameter child), ang background painter ay ipinapakita sa ilalim nito. Ito ay angkop para sa dekorasyon: mga progress bar, background pattern, watermark. foregroundPainter ay gumuhit pagkatapos ng anak ng CustomPaint, iyon ay, sa ibabaw nito. Ginagamit ito para sa mga overlay: glare, mask, measuring ruler, annotations.

Ang pagkakaiba sa pagitan ng painter at foregroundPainter ay kritikal para sa Z-order. Kung kailangan gumuhit ng isang bagay sa likod ng nilalaman — gamitin ang painter. Kung sa ibabaw ng nilalaman — foregroundPainter. Sa ilang kaso, maaari mong gamitin ang parehong painter nang sabay: background sa pamamagitan ng painter, label-overlay sa pamamagitan ng foregroundPainter. Ito ay nagpapahintulot sa paghihiwalay ng lohika ng iba't ibang graphical layer sa dalawang magkahiwalay na klase ng CustomPainter.

Ang parameter na size sa pamamaraan ng paint ay pareho para sa parehong painter at tinutukoy ng sukat ng lugar na inilaan para sa CustomPaint. Ang sukat ay maaaring itakda nang tahasan sa pamamagitan ng size parameter sa CustomPaint o hindi tahasan sa pamamagitan ng parent container. Kung ang size ay katumbas ng Size.zero, hindi tinatawag ang paint — nilalaktawan ng Flutter ang pag-render para sa zero area. Ang pag-uugali na ito ay dapat isaalang-alang kapag ang elemento ay lumilitaw nang may animation.

Pag-optimize ng pagganap ng CustomPainter

Ang pangunahing patakaran ng pagganap ng CustomPainter — huwag gumawa ng mga object sa loob ng pamamaraan ng paint. Ang Canvas, Paint, Path, Rect, Offset at iba pang mga object ng pagguhit ay dapat gawin sa constructor ng CustomPainter o i-cache. Ang paggawa ng mga object sa loob ng paint ay humahantong sa mga alokasyon sa bawat frame, na sa 60 frame bawat segundo ay nagdudulot ng madalas na garbage collection at pag-jerk ng animation (jank).

Ang pag-cache ng Path ay makabuluhang nagpapabilis sa pag-render ng mga paulit-ulit na kumplikadong contour. Kung ang contour ay hindi nagbabago sa pagitan ng mga frame (halimbawa, isang background grid), gawin ang Path nang isang beses at gamitin ito nang maraming beses. RepaintBoundary — widget na pambalot na pumipigil sa muling pagguhit ng CustomPainter kapag nagbago ang puno ng widget sa itaas. Kung ang CustomPainter ay static, balutin ito sa RepaintBoundary para sa paghihiwalay.

Para sa mga na-animate na CustomPainter na may madalas na muling pagguhit, gamitin ang Ticker o AnimationController na may shouldRepaint na nagbabalik ng true kapag nagbago ang animated na halaga. Optimal na ihambing ang animated na field sa shouldRepaint, hindi muling gumuhit sa bawat frame nang hindi kinakailangan. Rect caching para sa mga kumplikadong gradient: kung ang gradient ay hindi nagbabago ng mga kulay, maaari mong i-cache ang Shader sa pamamagitan ng Paint.shader.

Mga Madalas Itanong

Ano ang pagkakaiba sa pagitan ng CustomPainter at Canvas sa Flutter?

CustomPainter — ay isang contract class na tumutukoy kung ano at paano iguhit sa Canvas. Canvas — ang object ng pagguhit mismo na nagbibigay ng mga pamamaraan (drawCircle, drawLine atbp.). Natatanggap ng CustomPainter ang Canvas sa pamamagitan ng pamamaraan ng paint at pinamamahalaan ang paggamit nito. Ang isang Canvas ay maaaring gamitin ng iba't ibang CustomPainter sa iba't ibang oras.

Maaari bang gamitin ang CustomPainter nang walang CustomPaint?

Hindi, ang CustomPainter ay walang saysay kung walang CustomPaint. Ang CustomPaint ay ang widget na tumatawag sa pamamaraan ng paint ng CustomPainter at nagpapakita ng resulta sa screen. Kung walang CustomPaint, hindi malilikha ang Canvas at hindi maipapatupad ang paint. Maaari, gayunpaman, magpatupad ng sariling RenderObject na may Canvas, ngunit ito ay isang mas mababang antas na approach.

Paano i-animate ang CustomPainter?

Gamitin ang AnimationController na may Ticker, ipasa ang animated na halaga sa CustomPainter sa pamamagitan ng mga parameter ng constructor. Kapag nagbago ang halaga, tawagan ang setState() sa widget na naglalaman ng CustomPaint, na nagti-trigger ng shouldRepaint. Kung ang shouldRepaint ay nagbalik ng true, tinatawag ng system ang paint para sa bagong frame ng animation.

Bakit hindi nag-a-update ang CustomPainter kapag nagbago ang data?

Ang dahilan ay halos palaging shouldRepaint na nagbabalik ng false. Suriin kung ang mga field ng oldDelegate ay wastong inihahambing sa mga bagong halaga. Kung gumagamit ng mutable object, maaaring hindi makita ng shouldRepaint ang mga pagbabago dahil ang reference sa object ay nananatiling pareho. Gamitin ang == o mga immutable na object para sa tamang paghahambing.

Maaari bang gamitin ang CustomPainter para sa animation sa ReorderableListView?

Oo, ang CustomPainter ay ginagamit para sa pagguhit ng mga custom na dekorasyon sa mga kumplikadong listahan. Gayunpaman, tandaan na kapag nagre-reorder ng mga elemento, ang RepaintBoundary sa loob ng ListView ay nagca-cache ng pag-render ng bawat elemento. Ang CustomPainter ay dapat na magaan at hindi naglalaman ng mabibigat na operasyon sa paint upang hindi mapabagal ang drag animation.

Buod

  • CustomPainter — abstract na klase ng Flutter para sa custom na 2D rendering na may mga pamamaraan ng paint at shouldRepaint
  • CustomPaint — widget na tumatanggap ng painter (background) at foregroundPainter (foreground) para sa pagpapakita ng graphics
  • Canvas — object na may mga pamamaraan ng pagguhit: drawLine, drawCircle, drawPath, drawRect, drawArc at iba pa
  • Paint — klase na tumutukoy sa estilo ng pagguhit: kulay, kapal, estilo (fill/stroke), transparency at blending mode
  • shouldRepaint — pamamaraan ng optimisasyon na nagbabalik ng true lamang kapag nagbago ang mga field na nakakaapekto sa rendering
  • Ang paggawa ng mga object sa loob ng paint ay ipinagbabawal — lahat ng Paint, Path, Rect ay dapat i-cache para sa 60 fps
  • RepaintBoundary — widget para sa paghihiwalay ng CustomPainter mula sa muling pagguhit ng puno ng widget sa itaas

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din