हिट टेस्टिंग और रीपेंट अनुकूलन
पेंटिंग को बेहतर प्रदर्शनशील बनाए रखने के लिए कस्टम हिट टेस्टिंग और shouldRepaint तर्क लागू कीजिए।
हिट टेस्टिंग और रीपेंट अनुकूलन, CoddyKit पर Flutter मोबाइल विकास का एक निःशुल्क पाठ है। यह 4 में से 4वाँ पाठ है। इस अध्ययन पथ के 3 तक कोई भी पाठ पूरा पढ़ना निःशुल्क है — इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ व्यावहारिक अभ्यास भी उपलब्ध कराता है। यह Flutter मोबाइल विकास सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Flutter मोबाइल विकास पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
Hit Testing और Repaint क्यों महत्वपूर्ण हैं
जब आप CustomPainter से draw करते हैं, तो canvas पर आपका पूरा नियंत्रण होता है। लेकिन दो लागतें आसानी से नज़रअंदाज़ हो जाती हैं: hit testing (यह तय करना कि कौन-से pixels taps पर प्रतिक्रिया देंगे) और repainting (हर frame में आपके paint code को फिर से चलाना)।
- जो painter हमेशा
shouldRepaintसेtrueलौटाता है, वह हर rebuild पर repaint करता है और GPU तथा battery की अनावश्यक खपत करता है। - डिफ़ॉल्ट रूप से custom-painted region pointer events के लिए पारदर्शी होता है, इसलिए taps उसके पीछे वाले widgets तक पहुँच जाते हैं।
यह lesson दिखाता है कि custom drawings को interactive और कुशल, दोनों कैसे बनाया जाए।
CustomPainter की संरचना
एक CustomPainter दो मुख्य overrides उपलब्ध कराता है: drawing के लिए paint और यह तय करने के लिए shouldRepaint कि paint को कब फिर से चलाना है। Pointer logic के लिए वैकल्पिक hitTest भी होता है।
paint(Canvas canvas, Size size)— आपके drawing commands।shouldRepaint(covariant CustomPainter old)— केवल तबtrueलौटाएँ, जब visual inputs बदल गए हों।hitTest(Offset position)— pointer routing नियंत्रित करने के लिएtrue/false/nullलौटाएँ।
class CirclePainter extends CustomPainter {
final Color color;
final double radius;
CirclePainter({required this.color, required this.radius});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()..color = color;
canvas.drawCircle(size.center(Offset.zero), radius, paint);
}
@override
bool shouldRepaint(covariant CirclePainter old) =>
old.color != color || old.radius != radius;
}shouldRepaint: मुख्य Optimization
shouldRepaint को तब कॉल किया जाता है जब CustomPaint को नया पेंटर इंस्टेंस दिया जाता है। यदि यह false लौटाता है, तो Flutter पेंट चरण को छोड़ देता है और कैश की गई लेयर का फिर से उपयोग करता है।
- केवल उन्हीं फ़ील्ड की तुलना करें जो पिक्सेल को प्रभावित करती हैं।
- हर बार बिना शर्त
trueलौटाने से यह अनुकूलन निष्प्रभावी हो जाता है। - किसी बदलाव के बाद भी
falseलौटाने पर पुराने, स्थिर दृश्य दिखाई देते हैं।
पहचान की नहीं, मानों की तुलना करें — समान फ़ील्ड वाले दो पेंटर इंस्टेंस को false देना चाहिए।
@override
bool shouldRepaint(covariant CirclePainter old) {
// Repaint ONLY when a visual input differs.
return old.color != color || old.radius != radius;
}
// Anti-pattern: always repaints, no matter what.
// bool shouldRepaint(old) => true;रीपेंट सीमाएँ काम को अलग रखती हैं
यदि आपका पेंटर बार-बार बनने वाले उपवृक्ष के साथ एक ही लेयर साझा करता है, तो सही shouldRepaint भी मदद नहीं कर सकता। किसी चाइल्ड के साथ उपयोग किए जाने पर CustomPaint अपने-आप स्वयं को RepaintBoundary में लपेट देता है, लेकिन स्वतंत्र पेंटर के लिए आपको अक्सर इसे स्पष्ट रूप से जोड़ना पड़ता है।
RepaintBoundaryपेंट किए गए क्षेत्र को अपनी कंपोज़िटिंग लेयर देता है।- सीमा के भीतर होने वाला रीपेंट पैरेंट या सहोदर विजेट को रीपेंट करने के लिए बाध्य नहीं करता।
- कौन-सी लेयर चमक रही हैं, यह देखने के लिए Flutter DevTools का "Highlight Repaints" ओवरले उपयोग करें।
RepaintBoundary(
child: CustomPaint(
size: const Size(200, 200),
painter: CirclePainter(color: Colors.blue, radius: 60),
),
)डिफ़ॉल्ट हिट टेस्टिंग व्यवहार
अपने-आप CustomPaint पेंट किए गए आकारों पर पॉइंटर इवेंट कैप्चर नहीं करता — इसका hitTest डिफ़ॉल्ट रूप से null लौटाता है, जिसका अर्थ है "डिफ़ॉल्ट बॉक्स व्यवहार को सौंप दें।" ड्रॉइंग को टैप योग्य बनाने के लिए उन्हें जेस्चर डिटेक्टर में लपेटें और/या hitTest को ओवरराइड करें।
trueलौटाएँ: यह स्थान हिट हुआ; इवेंट को यहीं संभालें।falseलौटाएँ: यह हिट नहीं हुआ; इवेंट को पीछे के विजेट तक जाने दें।nullलौटाएँ: डिफ़ॉल्ट का उपयोग करें (यदि बॉक्स अपारदर्शी है, तो पूरा सीमाबद्ध बॉक्स हिट माना जाता है)।
सटीक hitTest लागू करना
आयताकार सीमाओं के बजाय वास्तविक खींचे गए आकार तक टैप सीमित करने के लिए hitTest को ओवरराइड करें। वृत्त के लिए केंद्र से दूरी की तुलना त्रिज्या से करें।
इससे सीमाबद्ध बॉक्स के कोनों पर हुए स्पर्श पीछे मौजूद वस्तु तक पहुँच जाते हैं, जो गैर-आयताकार कला के लिए स्वाभाविक लगता है।
class CirclePainter extends CustomPainter {
final Color color;
final double radius;
final Offset center;
CirclePainter({required this.color, required this.radius, required this.center});
@override
void paint(Canvas canvas, Size size) {
canvas.drawCircle(center, radius, Paint()..color = color);
}
@override
bool hitTest(Offset position) {
// True only inside the circle, not the whole box.
return (position - center).distance <= radius;
}
@override
bool shouldRepaint(covariant CirclePainter old) =>
old.color != color || old.radius != radius || old.center != center;
}Flutter के बिना दूरी का मॉडल बनाना
वृत्ताकार हिट टेस्टिंग के पीछे का गणित केवल यूक्लिडीय दूरी है। यह शुद्ध-Dart मॉडल है, जिसे आप hitTest में जोड़ने से पहले तर्क की जाँच के लिए किसी भी जज पर चला सकते हैं।
कोई बिंदु वृत्त के भीतर तब होता है जब उसकी केंद्र से दूरी त्रिज्या से कम या उसके बराबर हो।
import 'dart:math';
bool insideCircle(double px, double py, double cx, double cy, double r) {
final dx = px - cx;
final dy = py - cy;
return sqrt(dx * dx + dy * dy) <= r;
}
void main() {
const cx = 100.0, cy = 100.0, r = 60.0;
print(insideCircle(120, 110, cx, cy, r)); // true (inside)
print(insideCircle(10, 10, cx, cy, r)); // false (corner)
print(insideCircle(160, 100, cx, cy, r)); // true (on edge)
}Path.contains के साथ हिट टेस्टिंग
मनमाने आकारों के लिए paint में Path बनाएँ और Path.contains के माध्यम से उसे hitTest में फिर से उपयोग करें। पाथ को फ़ील्ड के रूप में रखने से हर फ़्रेम में उसे दो बार बनाने से बचा जा सकता है।
path.contains(position)तबtrueलौटाता है जब बिंदु भरे हुए क्षेत्र के भीतर हो।- पाथ को कैश करें; ज्यामिति के इनपुट बदलने पर ही उसे फिर बनाएँ।
class StarPainter extends CustomPainter {
final Path _path;
final Color color;
StarPainter({required this.color, required Size size})
: _path = _buildStar(size);
static Path _buildStar(Size size) {
final p = Path();
p.moveTo(size.width / 2, 0);
p.lineTo(size.width, size.height);
p.lineTo(0, size.height);
p.close();
return p;
}
@override
void paint(Canvas canvas, Size size) {
canvas.drawPath(_path, Paint()..color = color);
}
@override
bool hitTest(Offset position) => _path.contains(position);
@override
bool shouldRepaint(covariant StarPainter old) => old.color != color;
}केवल एनीमेशन टिक पर रीपेंट करना
एनीमेटेड पेंटर के लिए एनीमेशन चलाने वाले Listenable (जैसे AnimationController) को CustomPainter के repaint सुपर-पैरामीटर में दें। इसके बाद पूरा विजेट ट्री बनाए बिना, एनीमेशन के हर टिक पर पेंटर रीपेंट होता है।
super(repaint: animation)पेंटर को सीधे सुनने के लिए जोड़ता है।- इससे
setStateकी आवश्यकता नहीं रहती और हर फ़्रेम पर सहोदर विजेट फिर से नहीं बनते।
class PulsePainter extends CustomPainter {
final Animation<double> animation;
PulsePainter(this.animation) : super(repaint: animation);
@override
void paint(Canvas canvas, Size size) {
final r = 20 + animation.value * 40;
canvas.drawCircle(
size.center(Offset.zero), r, Paint()..color = Colors.teal);
}
// No need to compare values: the repaint Listenable drives it.
@override
bool shouldRepaint(covariant PulsePainter old) => false;
}जेस्चर को पेंटर से जोड़ना
पेंटर की हिट टेस्टिंग यह तय करती है कि पेंट किया गया क्षेत्र पॉइंटर के लिए अपारदर्शी है या नहीं, लेकिन प्रतिक्रिया देने के लिए आपको फिर भी एक GestureDetector जोड़ना होगा। दोनों को मिलाएँ: सटीक hitTest और डिटेक्टर आकार के अनुसार सही टैप उपलब्ध कराते हैं।
- डिटेक्टर का
onTapDownस्थानीयOffsetदेता है। - किस उप-आकार पर हिट हुआ, यह पहचानने के लिए आप वही ज्यामितीय जाँच फिर चला सकते हैं।
GestureDetector(
behavior: HitTestBehavior.deferToChild,
onTapUp: (details) {
final local = details.localPosition;
if ((local - center).distance <= radius) {
debugPrint('Circle tapped at $local');
}
},
child: CustomPaint(
size: const Size(200, 200),
painter: CirclePainter(
color: Colors.blue, radius: 60, center: const Offset(100, 100)),
),
)रीपेंट अनुकूलन की त्वरित जाँच-सूची
प्रदर्शन-सक्षम कस्टम पेंटिंग के लिए इसे एक व्यावहारिक जाँच-सूची के रूप में अपनाएँ:
shouldRepaintमें मानों की तुलना करें — कभी भी हर स्थिति मेंtrueन लौटाएँ।- एनीमेशन के लिए
setStateके बजायrepaint:का उपयोग करें। - पेंट की गई लेयर को अलग रखने के लिए
RepaintBoundaryमें लपेटें। PathऔरPaintऑब्जेक्ट कैश करें; हर फ़्रेम में नए ऑब्जेक्ट न बनाएँ।- गैर-आयताकार कला के खाली स्थान से इवेंट आगे जाने देने के लिए
hitTestको ओवरराइड करें। - DevTools के रीपेंट हाइलाइट और टाइमलाइन से प्रोफ़ाइल करें।
त्वरित जाँच: shouldRepaint
सोचें कि पेंटिंग को बेहतर प्रदर्शन के साथ बनाए रखने के लिए आपके shouldRepaint कार्यान्वयन को क्या लौटाना चाहिए।
पुनरावलोकन
आपने सीखा कि कस्टम-पेंट किए गए Flutter UI को इंटरैक्टिव और तेज़, दोनों कैसे बनाए रखें:
- shouldRepaint को केवल दृश्य इनपुट की मान के आधार पर तुलना करनी चाहिए और केवल बदलाव होने पर
trueलौटाना चाहिए। - hitTest पॉइंटर का मार्ग नियंत्रित करता है: सटीक आकार-जाँच गैर-आयताकार कला के अनावश्यक टैप को आगे जाने देती है।
- Path.contains और दूरी का गणित आकार के अनुसार सटीक हिट पहचान देते हैं; पाथ को कैश करें।
- RepaintBoundary पेंट की गई लेयर को अलग रखता है, इसलिए रीपेंट का प्रभाव आगे नहीं फैलता।
- repaint: एनीमेशन को सीधे पेंटर से जोड़ता है और पूरे विजेट ट्री को फिर से बनाने से बचाता है।
साथ मिलकर ये तकनीकें बेकार फ़्रेम हटाती हैं और आपके कैनवास ड्रॉइंग को स्वाभाविक तथा तुरंत प्रतिक्रिया देने वाला बनाती हैं।
एआई शिक्षक के साथ Dart सीखें — निःशुल्क
अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।
- पाठ्यक्रम
- 22
- पाठ
- 88
अक्सर पूछे जाने वाले प्रश्न
क्या “हिट टेस्टिंग और रीपेंट अनुकूलन” पाठ निःशुल्क है?
हाँ — Flutter मोबाइल विकास अध्ययन पथ के 3 तक कोई भी पाठ, जिसमें “हिट टेस्टिंग और रीपेंट अनुकूलन” भी शामिल है, यहाँ वेब पर पूरा पढ़ना निःशुल्क है। इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ इंटरैक्टिव अभ्यास भी उपलब्ध कराता है। Flutter मोबाइल विकास पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
“हिट टेस्टिंग और रीपेंट अनुकूलन” में मैं क्या सीखूँगा?
पेंटिंग को बेहतर प्रदर्शनशील बनाए रखने के लिए कस्टम हिट टेस्टिंग और shouldRepaint तर्क लागू कीजिए। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Flutter मोबाइल विकास का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।
क्या Flutter मोबाइल विकास शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?
पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Flutter मोबाइल विकास शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 4वाँ पाठ है।
“हिट टेस्टिंग और रीपेंट अनुकूलन” पाठ पूरा करने में कितना समय लगता है?
CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।
क्या मैं इस Flutter मोबाइल विकास पाठ में कोड लिख और चला सकता हूँ?
हाँ। हर Flutter मोबाइल विकास पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।
इस पाठ्यक्रम के सभी पाठ
- Canvas API: पथ, पेंट और शेडर
- इंटरैक्टिव कस्टम चार्ट विजेट बनाना
- क्लिपिंग, ब्लेंड मोड और लेयर कंपोज़िटिंग
- हिट टेस्टिंग और रीपेंट अनुकूलन