CustomPainter Flutter SDK का एक एब्सट्रैक्ट क्लास है जो डेवलपर्स को Canvas पर कस्टम 2D ग्राफिक्स रेंडर करने का पूर्ण नियंत्रण देता है। डेवलपर CustomPainter का उपवर्ग बनाता है और दो अनिवार्य विधियाँ लागू करता है: paint(Canvas, Size) और shouldRepaint(covariant CustomPainter oldDelegate)। Flutter API डॉक्यूमेंटेशन (2026) के अनुसार, CustomPainter का उपयोग CustomPaint विजेट के साथ किया जाता है, जो प्रत्येक एनिमेशन फ्रेम या स्थिति परिवर्तन पर प्रदान किए गए CustomPainter ऑब्जेक्ट को रेंडरिंग सौंपता है।
मुख्य बातें
CustomPainter कस्टम 2D ग्राफिक्स लागू करने के लिए Flutter का आधार क्लास है। यह Android में onDraw को ओवरराइड करने के दृष्टिकोण को बदलता है, जो अधिक लचीला और घोषणात्मक रेंडरिंग मॉडल प्रदान करता है। डेवलपर CustomPainter का उपवर्ग बनाता है, paint विधि को ओवरराइड करता है जहाँ वह Canvas और Size प्राप्त करता है, और Canvas पर सभी ड्रॉइंग ऑपरेशन करता है। CustomPaint विजेट paint कॉल का प्रबंधन करता है और परिणाम को विजेट ट्री में एकीकृत करता है।
CustomPainter और Canvas के माध्यम से सीधे ड्रॉइंग के बीच मुख्य अंतर रेंडरिंग लॉजिक (paint) और पुनः चित्रण ट्रिगर (shouldRepaint) का पृथक्करण है। Flutter सिस्टम हर बार जब पैरेंट विजेट बदलता है तो shouldRepaint को कॉल करता है। यदि shouldRepaint false लौटाता है, तो paint कॉल नहीं किया जाता है, जिससे संसाधन बचते हैं। यह तंत्र RenderObject में shouldRebuild के समान है और अपने तीन पेड़ों (Widget, Element, RenderObject) के साथ Flutter आर्किटेक्चर का हिस्सा है।
CustomPaint एक विजेट है जो painter (पृष्ठभूमि परत) और foregroundPainter(अग्रभूमि परत) पैरामीटर स्वीकार करता है। दोनों पैरामीटर CustomPainter ऑब्जेक्ट स्वीकार करते हैं। पृष्ठभूमि painter CustomPaint के चाइल्ड विजेट से पहले चित्रित किया जाता है, और foregroundPainter बाद में। यह CustomPaint को सजावटी पृष्ठभूमि या ओवरले वाले कंटेनर के रूप में उपयोग करने की अनुमति देता है, बिना अंदर सामान्य विजेट एम्बेड करने की क्षमता खोए।
Canvas Flutter में केंद्रीय ड्रॉइंग ऑब्जेक्ट है, जो ग्राफिक्स सतह को समाहित करता है। यह लगभग 40 ड्रॉइंग विधियाँ प्रदान करता है: drawLine, drawCircle, drawRect, drawPath, drawArc, drawImage, drawPicture, drawPoints और अन्य। Flutter में Canvas Android Canvas में समान क्लास से मेल खाता है लेकिन Dart आर्किटेक्चर और Flutter Engine के अनुकूल है। Canvas एक समन्वय प्रणाली में काम करता है जहाँ मूल बिंदु (0, 0) ऊपरी बाएँ कोना है।
Paint — paint() विधि से भ्रमित न हों — एक क्लास है जो ड्रॉइंग शैली को परिभाषित करता है: रंग (color), रेखा मोटाई (strokeWidth), शैली (style: fill या stroke), अपारदर्शिता, सम्मिश्रण मोड (blendMode) और एंटी-अलियासिंग मास्क। Paint ड्रॉइंग से पहले कॉन्फ़िगर किया जाता है और Canvas विधियों में पास किया जाता है। महत्वपूर्ण: Paint एक परिवर्तनीय ऑब्जेक्ट है, लेकिन इसे एक बार बनाने और केवल आवश्यक पैरामीटर बदलकर पुनः उपयोग करने की अनुशंसा की जाती है।
| Canvas विधि | उद्देश्य | पैरामीटर |
|---|---|---|
| drawCircle | वृत्त बनाना | Offset center, double radius, Paint paint |
| drawLine | रेखा खंड बनाना | Offset p1, Offset p2, Paint paint |
| drawRect | आयत बनाना | Rect rect, Paint paint |
| drawPath | मनमाना पथ बनाना | Path path, Paint paint |
| drawArc | चाप या सेक्टर बनाना | Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint |
| drawRRect | गोल कोनों वाला आयत | RRect rrect, Paint paint |
| drawOval | अंडाकार बनाना | Rect rect, Paint paint |
| drawImage | Image से चित्र बनाना | Image image, Offset p, Paint paint |
Canvas समन्वय प्रणाली रूपांतरण का समर्थन करता है: translate(double dx, double dy) मूल बिंदु को स्थानांतरित करता है; rotate(double radians) सिस्टम को घुमाता है; scale(double sx, double sy) स्केल करता है; skew(double sx, double sy) झुकाता है। रूपांतरण से पहले, save() के माध्यम से Canvas स्थिति को सहेजने और पूरा होने के बाद restore() के माध्यम से इसे पुनर्स्थापित करने की अनुशंसा की जाती है। यह बाद के paint कॉल में रूपांतरणों के संचय को रोकता है।
paint(Canvas canvas, Size size) अनिवार्य विधि है जो सभी ड्रॉइंग लॉजिक को लागू करती है। canvas पैरामीटर ड्रॉइंग के लिए ग्राफिक्स सतह है। size पैरामीटर ड्रॉइंग के लिए आवंटित क्षेत्र का आकार है (तार्किक पिक्सेल में चौड़ाई और ऊँचाई)। Canvas पूर्व-कॉन्फ़िगर किया गया है ताकि मूल बिंदु (0,0) ड्रॉइंग क्षेत्र के ऊपरी बाएँ कोने से मेल खाए। सभी निर्देशांक इस मूल बिंदु के सापेक्ष निर्दिष्ट किए जाते हैं।
shouldRepaint(covariant CustomPainter oldDelegate) एक अनिवार्य विधि है जो पुनः चित्रण आवृत्ति को अनुकूलित करती है। Flutter प्रत्येक विजेट ट्री अपडेट पर shouldRepaint को कॉल करता है जो CustomPainter को प्रभावित करता है। यदि विधि false लौटाती है, तो पहले से रेंडर की गई छवि को मान्य माना जाता है और paint कॉल नहीं किया जाता है। सामान्य कार्यान्वयन: return oldDelegate.someField != someField — पुनः चित्रण की आवश्यकता निर्धारित करने के लिए पुराने और नए painter के फ़ील्ड की तुलना।
एनिमेटेड या लगातार बदलती छवियों (घड़ियाँ, लोडिंग संकेतक, चार्ट) के लिए shouldRepaint को प्रत्येक स्थिति परिवर्तन पर true लौटाना चाहिए। यदि ऑब्जेक्ट स्थिर है (लोगो, आइकन, पृष्ठभूमि), तो shouldRepaint पहले रेंडर के बाद false लौटाता है। Flutter स्वचालित रूप से paint परिणाम को कैश करता है और केवल आकार, अपारदर्शिता या shouldRepaint कॉल बदलने पर पुनः चित्रित करता है।
आइए GaugePainter बनाएँ — एनिमेटेड भराव वाला एक कस्टम वृत्ताकार गेज। CustomPainter वर्तमान मान (0.0 से 1.0 तक प्रगति) स्वीकार करता है और ग्रेडिएंट के साथ एक चाप बनाता है। shouldRepaint विधि अनुकूलन के लिए प्रगति मान की तुलना करती है। CustomPaint को ड्रॉइंग क्षेत्र को सीमित करने के लिए size पैरामीटर के साथ विजेट ट्री में रखा जाता है।
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;
}
}
उदाहरण Path का उपयोग करके तरंग चार्ट बनाता है। Path रेखाओं, बेज़ियर वक्रों और चापों से मनमाने आकार बनाने की अनुमति देता है। आकार बनाने के बाद, इसे रंग से भरा जाता है या रेखा से रेखांकित किया जाता है। उदाहरण में, चार्ट तरंग आकार का अनुकरण करने वाले बिंदुओं की एक सरणी से बनाया गया है।
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 (पृष्ठभूमि) CustomPaint के चाइल्ड विजेट से पहले चित्रित किया जाता है। यदि CustomPaint में चाइल्ड विजेट (child पैरामीटर) है, तो पृष्ठभूमि painter उसके नीचे प्रदर्शित होता है। यह सजावट के लिए उपयुक्त है: प्रगति पट्टियाँ, पृष्ठभूमि पैटर्न, वॉटरमार्क। foregroundPainter चाइल्ड विजेट के बाद चित्रित किया जाता है, अर्थात उसके ऊपर। इसका उपयोग ओवरले के लिए किया जाता है: हाइलाइट, मास्क, मापने वाले रूलर, एनोटेशन।
painter और foregroundPainter के बीच अंतर Z-क्रम के लिए महत्वपूर्ण है। यदि आपको सामग्री के पीछे कुछ चित्रित करना है — painter का उपयोग करें। यदि सामग्री के ऊपर — foregroundPainter का। कुछ मामलों में, आप दोनों painter का एक साथ उपयोग कर सकते हैं: painter के माध्यम से पृष्ठभूमि, foregroundPainter के माध्यम से ओवरले लेबल। यह विभिन्न ग्राफिक परतों के तर्क को दो अलग CustomPainter क्लास में विभाजित करने की अनुमति देता है।
paint विधि में size पैरामीटर दोनों painter के लिए समान है और CustomPaint के लिए आवंटित क्षेत्र के आकार से निर्धारित होता है। आकार CustomPaint में size पैरामीटर के माध्यम से स्पष्ट रूप से या पैरेंट कंटेनर के माध्यम से अप्रत्यक्ष रूप से सेट किया जा सकता है। यदि आकार Size.zero है, तो paint कॉल नहीं किया जाता है — Flutter शून्य आकार वाले क्षेत्र के लिए रेंडरिंग छोड़ देता है। तत्व प्रकटन को एनिमेट करते समय इस व्यवहार पर विचार किया जाना चाहिए।
CustomPainter प्रदर्शन का मुख्य नियम paint विधि के अंदर ऑब्जेक्ट नहीं बनाना है। Canvas, Paint, Path, Rect, Offset और अन्य ड्रॉइंग ऑब्जेक्ट CustomPainter कंस्ट्रक्टर में बनाए जाने चाहिए या कैश किए जाने चाहिए। paint के अंदर ऑब्जेक्ट बनाने से प्रत्येक फ्रेम पर आवंटन होता है, जो 60 फ्रेम प्रति सेकंड पर बार-बार कचरा संग्रह और एनिमेशन जर्क (jank) का कारण बनता है।
Path कैशिंग दोहराए जाने वाले जटिल पथों के रेंडरिंग को काफी तेज करता है। यदि पथ फ्रेम के बीच नहीं बदलता है (उदाहरण के लिए, पृष्ठभूमि ग्रिड), तो Path को एक बार बनाएँ और इसे कई बार पुनः उपयोग करें। RepaintBoundary एक रैपर विजेट है जो ऊपरी विजेट ट्री बदलने पर CustomPainter को पुनः चित्रित होने से रोकता है। यदि CustomPainter स्थिर है, तो इसे अलग करने के लिए RepaintBoundary में लपेटें।
बार-बार पुनः चित्रण वाले एनिमेटेड CustomPainter के लिए, shouldRepaint के साथ Ticker या AnimationController का उपयोग करें जो एनिमेटेड मान के प्रत्येक परिवर्तन पर true लौटाता है। shouldRepaint में एनिमेटेड फ़ील्ड की तुलना करना इष्टतम है, न कि बिना आवश्यकता के प्रत्येक फ्रेम पर पुनः चित्रित करना। जटिल ग्रेडिएंट के लिए Rect कैशिंग: यदि ग्रेडिएंट रंग नहीं बदलते हैं, तो आप Paint.shader के माध्यम से Shader को कैश कर सकते हैं।
अक्सर पूछे जाने वाले प्रश्न
CustomPainter एक अनुबंध क्लास है जो परिभाषित करता है कि Canvas पर क्या और कैसे चित्रित करना है। Canvas स्वयं ड्रॉइंग ऑब्जेक्ट है, जो विधियाँ प्रदान करता है (drawCircle, drawLine आदि)। CustomPainter paint विधि के माध्यम से Canvas प्राप्त करता है और इसके उपयोग को नियंत्रित करता है। एक Canvas का उपयोग अलग-अलग समय पर विभिन्न CustomPainter द्वारा किया जा सकता है।
नहीं, CustomPainter का CustomPaint के बिना कोई अर्थ नहीं है। CustomPaint वह विजेट है जो CustomPainter की paint विधि को कॉल करता है और परिणाम स्क्रीन पर प्रदर्शित करता है। CustomPaint के बिना, Canvas नहीं बनेगा और paint निष्पादित नहीं होगा। हालांकि, आप Canvas के साथ अपना स्वयं का RenderObject लागू कर सकते हैं, लेकिन यह निम्न-स्तरीय दृष्टिकोण है।
कंस्ट्रक्टर पैरामीटर के माध्यम से एनिमेटेड मान CustomPainter में पास करते हुए, Ticker के साथ AnimationController का उपयोग करें। जब मान बदलता है, तो CustomPaint वाले विजेट में setState() कॉल करें, जो shouldRepaint कॉल को ट्रिगर करता है। यदि shouldRepaint true लौटाता है, तो सिस्टम नए एनिमेशन फ्रेम के लिए paint कॉल करता है।
कारण लगभग हमेशा shouldRepaint का false लौटाना है। जाँच करें कि oldDelegate फ़ील्ड नए मानों के साथ सही ढंग से तुलना की जा रही हैं या नहीं। यदि परिवर्तनीय ऑब्जेक्ट का उपयोग किया जाता है, तो shouldRepaint परिवर्तनों का पता नहीं लगा सकता क्योंकि ऑब्जेक्ट संदर्भ समान रहता है। सही तुलना के लिए == या अपरिवर्तनीय ऑब्जेक्ट का उपयोग करें।
हाँ, CustomPainter का उपयोग जटिल सूचियों में कस्टम सजावट चित्रित करने के लिए किया जाता है। हालांकि, ध्यान दें कि आइटम पुनर्क्रमित करते समय, ListView के अंदर RepaintBoundary प्रत्येक आइटम की रेंडरिंग कैश करता है। CustomPainter हल्का होना चाहिए और ड्रैग एनिमेशन को धीमा न करने के लिए paint में भारी ऑपरेशन नहीं होने चाहिए।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें