CustomPainter — Flutter SDK-dan abstrakt sinifdir, tərtibatçılara Canvas-da xüsusi 2D qrafikasının çəkilməsi üzərində tam nəzarət verir. Tərtibatçı CustomPainter alt sinfini yaradır və iki məcburi metodu həyata keçirir: paint(Canvas, Size) və shouldRepaint(covariant CustomPainter oldDelegate). Flutter API Documentation (2026) məlumatına görə, CustomPainter CustomPaint vidjeti ilə birlikdə istifadə olunur, o, hər animasiya kadrında və ya vəziyyət dəyişikliyində çəkməni CustomPainter obyektinə həvalə edir.
Əsas məqamlar
CustomPainter — Flutter-da ixtiyari 2D qrafikasının tətbiqi üçün əsas sinifdir. O, Android-də onDraw-ı ləğv etmək yanaşmasını əvəz edərək, daha çevik və deklarativ çəkmə modeli təqdim edir. Tərtibatçı CustomPainter alt sinfini yaradır, paint metodunu ləğv edir, orada Canvas və Size alır və Canvas-da bütün rəsm əməliyyatlarını yerinə yetirir. CustomPaint vidjeti paint-in çağırılmasını idarə edir və nəticəni vidjet ağacına inteqrasiya edir.
CustomPainter ilə birbaşa Canvas vasitəsilə rəsm çəkmə arasında əsas fərq — çəkmə məntiqinin (paint) və yenidən çəkmə tetikleyicisinin (shouldRepaint) ayrılmasıdır. Flutter sistemi valideyn vidjet hər dəyişdikdə shouldRepaint-i çağırır. shouldRepaint false qaytarırsa, paint çağırılmır, bu da resurslara qənaət edir. Bu mexanizm RenderObject-də shouldRebuild-ə bənzəyir və Flutter memarlığının üç ağacının (Widget, Element, RenderObject) bir hissəsidir.
CustomPaint — painter (fon qatı) və foregroundPainter (ön qat) parametrlərini qəbul edən vidjetdir. Hər iki parametr CustomPainter obyektlərini qəbul edir. Fon painteri CustomPaint-in uşaq vidjetindən əvvəl çəkir, foregroundPainter isə ondan sonra. Bu, CustomPaint-i dekorativ fon və ya örtük ilə konteyner kimi istifadə etməyə imkan verir, adi vidjetləri içəridə yerləşdirmək imkanını itirmədən.
Canvas — Flutter-da rəsm üçün mərkəzi obyektdir, qrafik səthi inkapsulyasiya edir. O, təxminən 40 rəsm metodu təqdim edir: drawLine, drawCircle, drawRect, drawPath, drawArc, drawImage, drawPicture, drawPoints və digərləri. Flutter-də Canvas Android Canvas-dəki analoji sinfə uyğundur, lakin Dart və Flutter Engine memarlığına uyğunlaşdırılmışdır. Canvas koordinat sistemində işləyir, burada başlanğıc (0, 0) yuxarı sol küncdür.
Paint — paint() metodu ilə qarışdırmayın — rəsm stilini təyin edən sinifdir: rəng (color), xətt qalınlığı (strokeWidth), stil (style: fill və ya stroke), şəffaflıq, qarışdırma rejimi (blendMode) və hamarlama maskası. Paint rəsmdən əvvəl konfiqurasiya edilir və Canvas metodlarına ötürülür. Vacib: Paint dəyişdirilə bilən obyektdir, lakin onu bir dəfə yaradıb təkrar istifadə etmək, yalnız lazımi parametrləri dəyişmək tövsiyə olunur.
| Canvas metodu | Təyinat | Parametrlər |
|---|---|---|
| drawCircle | Dairə çəkmək | Offset center, double radius, Paint paint |
| drawLine | Xətt çəkmək | Offset p1, Offset p2, Paint paint |
| drawRect | Düzbucaqlı çəkmək | Rect rect, Paint paint |
| drawPath | İxtiyari kontur çəkmək | Path path, Paint paint |
| drawArc | Qövs və ya sektor çəkmək | Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint |
| drawRRect | Dairəvi künclü düzbucaqlı | RRect rrect, Paint paint |
| drawOval | Oval çəkmək | Rect rect, Paint paint |
| drawImage | Image-dən şəkil çəkmək | Image image, Offset p, Paint paint |
Canvas koordinat sisteminin transformasiyalarını dəstəkləyir: translate(double dx, double dy) koordinat başlanğıcını yerdəyişdirir; rotate(double radians) sistemi fırladır; scale(double sx, double sy) miqyaslayır; skew(double sx, double sy) əyir. Transformasiyadan əvvəl Canvas vəziyyətini save() ilə saxlamaq, bitdikdən sonra isə restore() ilə bərpa etmək tövsiyə olunur. Bu, sonrakı paint çağırışlarında transformasiyaların yığılmasının qarşısını alır.
paint(Canvas canvas, Size size) — bütün çəkmə məntiqinin həyata keçirildiyi məcburi metoddur. canvas parametri — rəsm üçün qrafik səthdir. size parametri — rəsm üçün ayrılmış sahənin ölçüsüdür (en və hündürlük məntiqi piksellərdə). Canvas əvvəlcədən konfiqurasiya edilmişdir ki, koordinat başlanğıcı (0,0) rəsm sahəsinin yuxarı sol küncünə uyğun gəlir. Bütün koordinatlar bu başlanğıca nisbətən təyin edilir.
shouldRepaint(covariant CustomPainter oldDelegate) — yenidən çəkmə tezliyini optimallaşdıran məcburi metoddur. Flutter vidjet ağacının CustomPainter-ə təsir edən hər yeniləməsində shouldRepaint-i çağırır. Metod false qaytarırsa, artıq çəkilmiş şəkil etibarlı sayılır və paint çağırılmır. Tipik tətbiq: return oldDelegate.someField != someField — yenidən çəkmə ehtiyacını müəyyən etmək üçün köhnə və yeni painter-in sahələrinin müqayisəsi.
Animasiya olunan və ya daim dəyişən şəkillər üçün (saatlar, yüklənmə göstəriciləri, qrafiklər) shouldRepaint hər vəziyyət dəyişikliyində true qaytarmalıdır. Obyekt statikdirsə (loqo, ikon, fon), shouldRepaint ilk çəkmədən sonra false qaytarır. Flutter paint nəticəsini avtomatik keşləyir və yalnız ölçü, şəffaflıq dəyişdikdə və ya shouldRepaint çağırıldıqda yenidən çəkir.
GaugePainter yaradaq — animasiya olunan doldurma ilə xüsusi dairəvi göstərici. CustomPainter cari dəyəri (progress 0.0-dan 1.0-a qədər) qəbul edir və gradientlə qövs çəkir. shouldRepaint metodunda optimallaşdırma üçün progress dəyəri müqayisə edilir. CustomPaint vidjet ağacına rəsm sahəsini məhdudlaşdırmaq üçün size parametri ilə yerləşdirilir.
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;
}
}
Nümunə Path istifadə edərək dalğa qrafiki çəkir. Path xətlərdən, Bezier əyrilərindən və qövslərdən ixtiyari konturlar qurmağa imkan verir. Kontur qurulduqdan sonra rənglə doldurulur və ya xətt ilə konturlanır. Nümunədə qrafik dalğa formasını təqlid edən nöqtələr massivi əsasında qurulur.
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;
}
}
painter (fon) CustomPaint-in uşaq vidjetindən əvvəl çəkir. CustomPaint-in uşaq vidjeti varsa (child parametri), fon painteri onun altında göstərilir. Bu, dekorasiya üçün uyğundur: gedişat zolaqları, fon naxışları, su nişanları. foregroundPainter uşaq vidjetdən sonra, yəni onun üstündə çəkir. Üst qatlar üçün istifadə olunur: parıltılar, maskalar, ölçü xətləri, annotasiyalar.
Fərq painter və foregroundPainter arasında Z-order üçün kritikdir. Məzmunun arxasında bir şey çəkmək lazımdırsa — painter istifadə edin. Məzmunun üstündədirsə — foregroundPainter. Bəzi hallarda hər iki painter-dən eyni vaxtda istifadə etmək olar: fon painter vasitəsilə, etiket-örtük foregroundPainter vasitəsilə. Bu, müxtəlif qrafik qatlarının məntiqini iki ayrı CustomPainter sinfinə ayırmağa imkan verir.
size parametri paint metodunda hər iki painter üçün eynidir və CustomPaint üçün ayrılmış sahənin ölçüsü ilə müəyyən edilir. Ölçü CustomPaint-də size parametri ilə açıq şəkildə və ya valideyn konteyner vasitəsilə gizli şəkildə təyin edilə bilər. size Size.zero-a bərabərdirsə, paint çağırılmır — Flutter sıfır sahə üçün çəkməni buraxır. Bu davranış elementin animasiya olunan görünməsində nəzərə alınmalıdır.
Əsas qayda CustomPainter performansı — paint metodu daxilində obyektlər yaratmamaqdır. Canvas, Paint, Path, Rect, Offset və digər rəsm obyektləri CustomPainter konstruktorunda yaradılmalı və ya keşlənməlidir. paint daxilində obyekt yaratmaq hər kadrda alokasiyalara gətirib çıxarır ki, bu da saniyədə 60 kadrda tez-tez zibil yığımına və animasiyanın sıçrayışına (jank) səbəb olur.
Path keşlənməsi təkrarlanan mürəkkəb konturların çəkilməsini əhəmiyyətli dərəcədə sürətləndirir. Kontur kadrlar arasında dəyişmirsə (məsələn, fon toru), Path-i bir dəfə yaradın və dəfələrlə istifadə edin. RepaintBoundary — CustomPainter-in yuxarıdakı vidjet ağacı dəyişdikdə yenidən çəkilməsinin qarşısını alan sarğıcı vidjetdir. CustomPainter statikdirsə, onu təcrid etmək üçün RepaintBoundary-ə sarın.
Tez-tez yenidən çəkilən animasiya olunan CustomPainter üçün Ticker və ya AnimationController istifadə edin, shouldRepaint animasiya olunan dəyər dəyişdikdə true qaytarsın. Optimal olaraq shouldRepaint-də animasiya olunan sahəni müqayisə edin, hər kadrda lazımsız yerə yenidən çəkməyin. Mürəkkəb gradientlər üçün Rect keşlənməsi: gradient rəngləri dəyişmirsə, Paint.shader vasitəsilə Shader-i keşləmək olar.
Tez-tez verilən suallar
CustomPainter — Canvas-da nə və necə çəkiləcəyini təyin edən kontrakt sinifdir. Canvas — metodlar təqdim edən (drawCircle, drawLine və s.) rəsm obyektinin özüdür. CustomPainter Canvas-ı paint metodu vasitəsilə alır və onun istifadəsini idarə edir. Bir Canvas müxtəlif vaxtlarda müxtəlif CustomPainter tərəfindən istifadə edilə bilər.
Xeyr, CustomPainter CustomPaint olmadan məna kəsb etmir. CustomPaint — CustomPainter-in paint metodunu çağıran və nəticəni ekranda göstərən vidjetdir. CustomPaint olmadan Canvas yaradılmayacaq və paint icra olunmayacaq. Bununla belə, Canvas ilə öz RenderObject-unuzu tətbiq etmək olar, lakin bu, daha aşağı səviyyəli yanaşmadır.
AnimationController ilə Ticker istifadə edin, animasiya olunan dəyəri CustomPainter-ə konstruktor parametrləri vasitəsilə ötürün. Dəyər dəyişdikdə CustomPaint-i ehtiva edən vidjetdə setState() çağırın, bu shouldRepaint-i tetikleyir. shouldRepaint true qaytarırsa, sistem animasiyanın yeni kadrı üçün paint çağırır.
Səbəb demək olar ki, həmişə false qaytaran shouldRepaint-dir. oldDelegate sahələrinin yeni dəyərlərlə düzgün müqayisə edilib-edilmədiyini yoxlayın. Dəyişdirilə bilən obyekt istifadə olunursa, shouldRepaint dəyişiklikləri görməyə bilər, çünki obyektə istinad eyni qalır. Düzgün müqayisə üçün == və ya dəyişməz obyektlərdən istifadə edin.
Bəli, CustomPainter mürəkkəb siyahılarda xüsusi dekorasiyaların çəkilməsi üçün istifadə olunur. Bununla belə, elementlərin sıralanması zamanı ListView daxilində RepaintBoundary hər elementin çəkilməsini keşləyir. CustomPainter yüngül olmalı və paint-də ağır əməliyyatlar ehtiva etməməlidir ki, sürükləmə animasiyasını yavaşlatmasın.
Xülasə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun