Custom View Android में एक कस्टम इंटरफ़ेस घटक है, जो View क्लास या इसकी उपक्लासेस (Button, TextView, ImageView) से इनहेरिट करके और मुख्य मेथड्स को ओवरराइड करके बनाया जाता है: onDraw ड्राइंग के लिए, onMeasure आकार मापने के लिए और onTouchEvent टच हैंडलिंग के लिए। Google Android Developer Guide (2024) के अनुसार, Custom View का उपयोग तब किया जाता है जब मानक Android SDK घटक आवश्यक व्यवहार या दृश्य प्रदान नहीं करते — उदाहरण के लिए, कस्टम एनिमेशन, गैर-मानक आकार, विशेष चार्ट और गेम तत्व।
मुख्य बिंदु
Custom View एक क्लास है जो android.view.View (या इसकी उपक्लासेस में से एक) से इनहेरिट करती है और कस्टम ड्राइंग, माप और ईवेंट हैंडलिंग तर्क को लागू करने के लिए सिस्टम मेथड्स को ओवरराइड करती है। Custom View अद्वितीय UI घटक बनाने के लिए Android का एक मौलिक तंत्र है।
Android Custom View बनाने के दो दृष्टिकोण प्रदान करता है: View से इनहेरिट करना (onDraw के माध्यम से पूरी तरह से कस्टम ड्राइंग) और मौजूदा View उपक्लास से इनहेरिट करना (उदाहरण के लिए, बेस व्यवहार को बनाए रखते हुए कार्यक्षमता जोड़ने के लिए Button या TextView को ओवरराइड करना)।
बेसिक कंस्ट्रक्टर को Context और AttributeSet स्वीकार करना चाहिए — यह सिस्टम को XML मार्कअप से View बनाने की अनुमति देता है। यदि View केवल कोड से उपयोग किया जाएगा, तो Context वाला कंस्ट्रक्टर पर्याप्त है। स्टाइल वाला तीसरा कंस्ट्रक्टर Android थीम समर्थन के लिए आवश्यक है।
class CustomView
@JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = Color.BLUE
strokeWidth = 4f
style = Paint.Style.FILL
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawCircle(width / 2f,
height / 2f,
50f, paint)
}
}
न्यूनतम Custom View में एक कंस्ट्रक्टर और onDraw होता है। हालांकि, Android Layout सिस्टम में सही काम करने के लिए, onMeasure को भी ओवरराइड किया जाना चाहिए — अन्यथा View शून्य आकार के साथ प्रदर्शित हो सकता है या wrap_content लेआउट पैरामीटर के लिए गलत प्रतिक्रिया दे सकता है।
Google I/O 2023 के अनुसार, Google Play के शीर्ष 100 ऐप्स में से 65% में कस्टम Views का उपयोग किया जाता है। Custom View बनाने के सबसे सामान्य कारण: कस्टम एनिमेशन (35%), कस्टम चार्ट और आरेख (25%), विशेष नियंत्रण तत्व (20%) और ब्रांडेड घटक (20%)।
onMeasure वह मेथड है जिसमें View प्राप्त MeasureSpec (पैरेंट बाधाओं) के आधार पर अपने वांछित आयामों की रिपोर्ट करता है। उचित onMeasure कार्यान्वयन के बिना, View की wrap_content के साथ शून्य ऊंचाई हो सकती है या match_parent के साथ पूरी स्क्रीन क्षेत्र घेर सकता है।
MeasureSpec में एक मोड (EXACTLY, AT_MOST, UNSPECIFIED) और एक मान होता है। EXACTLY — पैरेंट ने सटीक आकार सेट किया (match_parent या निश्चित मान)। AT_MOST — पैरेंट ने अधिकतम सेट किया (wrap_content)। UNSPECIFIED — कोई प्रतिबंध नहीं (ScrollView, ListView)।
override fun onMeasure(
widthMeasureSpec: Int,
heightMeasureSpec: Int
) {
val desiredWidth = paddingLeft + paddingRight
+ DEFAULT_WIDTH
val desiredHeight = paddingTop + paddingBottom
+ DEFAULT_HEIGHT
val measuredWidth = MeasureSpec.getSize(widthMeasureSpec)
val modeWidth = MeasureSpec.getMode(widthMeasureSpec)
val resultWidth = when (modeWidth) {
MeasureSpec.EXACTLY -> measuredWidth
MeasureSpec.AT_MOST ->
desiredWidth.coerceAtMost(measuredWidth)
else -> desiredWidth
}
val resultHeight = resolveSize(desiredHeight,
heightMeasureSpec)
setMeasuredDimension(resultWidth, resultHeight)
}
resolveSize एक Android उपयोगिता मेथड है जो onMeasure कार्यान्वयन को सरल बनाता है। यह वांछित आकार और MeasureSpec लेता है और सही मान लौटाता है: EXACTLY के लिए — सटीक आकार, AT_MOST के लिए — वांछित और अधिकतम में से न्यूनतम, UNSPECIFIED के लिए — वांछित आकार।
onLayout View (ViewGroup नहीं) के लिए आमतौर पर ओवरराइड नहीं किया जाता — इसे पैरेंट द्वारा चाइल्ड तत्वों को स्थापित करने के लिए बुलाया जाता है। ViewGroup के लिए, onLayout अनिवार्य है — इसमें प्रत्येक चाइल्ड View के लिए layout() कॉल करना होता है।
onDraw Custom View का हृदय है। यह मेथड Android द्वारा प्रत्येक View पुनर्ड्रा पर बुलाया जाता है। इसे एक Canvas ऑब्जेक्ट पास किया जाता है, जिसके माध्यम से सभी ड्राइंग की जाती है: ज्यामितीय आकार, टेक्स्ट, पथ, Bitmap और एनिमेशन।
Canvas API सभी बुनियादी संचालन के लिए मेथड प्रदान करता है: drawCircle, drawRect, drawLine, drawPath, drawText, drawBitmap, drawArc, drawOval। शैली को कॉन्फ़िगर करने के लिए, Paint का उपयोग किया जाता है — एक ऑब्जेक्ट जो रंग, मोटाई, भरण शैली, फ़ॉन्ट, छाया और प्रभावों को परिभाषित करता है।
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// पृष्ठभूमि
canvas.drawRect(0f, 0f,
width.toFloat(), height.toFloat(), bgPaint)
// पाठ
canvas.drawText("Custom View",
paddingLeft.toFloat(),
paddingTop.toFloat() + textPaint.textSize,
textPaint)
// वृत्त
canvas.drawCircle(
width / 2f,
height / 2f,
radius, circlePaint)
// पथ (बेज़ियर वक्र)
val path = Path().apply {
moveTo(0f, height.toFloat())
quadTo(width / 2f, 0f,
width.toFloat(), height.toFloat())
}
canvas.drawPath(path, pathPaint)
}
Paint ड्राइंग शैली कॉन्फ़िगरेटर है। एंटी-अलियासिंग (Paint.ANTI_ALIAS_FLAG) चिकने किनारों के लिए अनिवार्य है। सबपिक्सेल टेक्स्ट (SUBPIXEL_TEXT_FLAG) टेक्स्ट गुणवत्ता में सुधार करता है। Style.FILL, STROKE और FILL_AND_STROKE यह निर्धारित करते हैं कि आकार भरा जाएगा, रेखांकित किया जाएगा या दोनों।
महत्वपूर्ण: onDraw में Paint, Path, Rect ऑब्जेक्ट न बनाएं — इससे ड्राइंग लूप में आवंटन होता है और कचरा संग्रह शुरू होता है, जो FPS को कम करता है। सभी ड्राइंग ऑब्जेक्ट कंस्ट्रक्टर या init मेथड में बनाएं। एनिमेशन के लिए, पुनर्ड्रा को ट्रिगर करने के लिए ValueAnimator या ObjectAnimator का उपयोग invalidate() के साथ करें।
कस्टम एट्रीब्यूट मानक android:layout_width या android:background की तरह XML मार्कअप से Custom View को कॉन्फ़िगर करने की अनुमति देते हैं। एट्रीब्यूट res/values/attrs.xml फ़ाइल में नाम, प्रकार और वैकल्पिक डिफ़ॉल्ट मान के साथ घोषित किए जाते हैं।
एट्रीब्यूट प्रकार: string, integer, float, boolean, color, dimension, enum, flag, fraction, reference (संसाधन संदर्भ)। प्रत्येक प्रकार के लिए, Android स्वचालित रूप से XML से मान पार्स करता है और इसे TypedArray को भेजता है।
<!-- res/values/attrs.xml -->
<resources>
<declare-styleable name="CustomView">
<attr name="circleColor"
format="color" />
<attr name="circleRadius"
format="dimension" />
<attr name="labelText"
format="string" />
<attr name="showAnimation"
format="बूलियन" />
</declare-styleable>
</resources>
Custom View कंस्ट्रक्टर में, एट्रीब्यूट context.obtainStyledAttributes के माध्यम से पढ़े जाते हैं, जो TypedArray लौटाता है। TypedArray टाइप किए गए एक्सेस मेथड प्रदान करता है: getColor, getDimension, getString, getBoolean, getInt। पढ़ने के बाद, संसाधन मुक्त करने के लिए TypedArray पर recycle() कॉल करना आवश्यक है।
init {
val typedArray = context.obtainStyledAttributes(
attrs,
R.styleable.CustomView
)
circleColor = typedArray.getColor(
R.styleable.CustomView_circleColor,
Color.BLUE
)
circleRadius = typedArray.getDimension(
R.styleable.CustomView_circleRadius,
50f
)
labelText = typedArray.getString(
R.styleable.CustomView_labelText
) ?: "Default"
typedArray.recycle()
}
XML में उपयोग: app नेमस्पेस जोड़ें (xmlns:app="http://schemas.android.com/apk/res-auto") और app:circleColor="@color/red" जैसे कस्टम एट्रीब्यूट का उपयोग करें। यदि attrs.xml में घोषणा सही है तो Android Studio ऑटोकम्पलीट करेगा और एट्रीब्यूट प्रकारों को मान्य करेगा।
onTouchEvent वह मेथड है जो View के प्रत्येक स्पर्श पर बुलाया जाता है। यह ईवेंट प्रकार (ACTION_DOWN, ACTION_MOVE, ACTION_UP, ACTION_CANCEL), निर्देशांक, दबाव और उंगलियों की संख्या (मल्टी-टच) के बारे में जानकारी के साथ एक MotionEvent ऑब्जेक्ट प्राप्त करता है।
जटिल जेस्चर (स्वाइप, पिंच, लॉन्ग प्रेस) को संभालने के लिए, onTouchEvent के साथ GestureDetector या ScaleGestureDetector का उपयोग करें। GestureDetector onSingleTapUp, onFling, onLongPress, onDoubleTap और अन्य मानक जेस्चर की पहचान को सरल बनाता है।
private val gestureDetector = GestureDetector(
context, object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(e: MotionEvent): Boolean {
handleTap(e.x, e.y)
return true
}
})
override fun onTouchEvent(event: MotionEvent): Boolean {
val handled = gestureDetector.onTouchEvent(event)
when (event.action) {
MotionEvent.ACTION_MOVE -> {
currentX = event.x
currentY = event.y
invalidate()
return true
}
}
return handled || super.onTouchEvent(event)
}
हिट-टेस्टिंग — यह निर्धारित करना कि स्पर्श View के किसी विशिष्ट क्षेत्र में आया है या नहीं। आयताकार क्षेत्रों के लिए, Rect.contains(x, y) का उपयोग करें। वृत्तों के लिए — केंद्र से दूरी की जाँच: sqrt(dx^2 + dy^2) < radius। मनमाने आकारों के लिए — Path.op() या Region.contains()।
मल्टी-टच MotionEvent.getPointerCount() और getPointerId(index) के माध्यम से संभाला जाता है। प्रत्येक उंगली को एक अद्वितीय ID मिलता है जो ACTION_DOWN से ACTION_POINTER_UP तक संरक्षित रहता है। ACTION_MOVE में सभी सक्रिय उंगलियों का डेटा हो सकता है — गति प्रक्षेप के लिए getHistoricalX/Y का उपयोग करें।
Custom View प्रदर्शन अड़चन बन सकता है यदि onDraw बार-बार बुलाया जाता है (एनिमेशन, स्क्रॉल) या इसमें भारी संचालन होते हैं। Android कस्टम घटक रेंडरिंग को अनुकूलित करने के लिए कई तंत्र प्रदान करता है।
View.setLayerType View रेंडरिंग को सॉफ़्टवेयर (LAYER_TYPE_SOFTWARE) या हार्डवेयर (LAYER_TYPE_HARDWARE) लेयर पर स्विच करने की अनुमति देता है। सॉफ़्टवेयर लेयर जटिल Canvas ग्राफ़िक्स के लिए उपयोगी है जो हार्डवेयर त्वरण द्वारा समर्थित नहीं हैं — उदाहरण के लिए, drawTextOnPath या जटिल Path प्रभाव।
invalidate(Rect) पूरे घटक के बजाय केवल View के निर्दिष्ट क्षेत्र को पुनर्ड्रा करता है। यह बड़े Custom Views (ग्राफ़िक्स, मैप्स, ड्राइंग कैनवस) के लिए महत्वपूर्ण है, जहां प्रत्येक फ्रेम का पूर्ण पुनर्ड्रा FPS गिरावट का कारण बनता है। vsync सिंक्रनाइज़ेशन के लिए postInvalidateOnAnimation() का उपयोग करें।
class EfficientCustomView
@JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
// कंस्ट्रक्टर में एक बार बनाए गए ऑब्जेक्ट
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val rect = Rect()
private val position = PointF()
fun updatePosition(x: Float, y: Float) {
position.set(x, y)
// केवल बिंदु के आसपास के क्षेत्र को पुनर्ड्रा करें
rect.set(
(x - 10).toInt(),
(y - 10).toInt(),
(x + 10).toInt(),
(y + 10).toInt()
)
invalidate(rect)
}
}
हार्डवेयर त्वरण Android 3.0+ (API 11+) पर डिफ़ॉल्ट रूप से सक्षम है। Canvas संचालन drawCircle, drawRect, drawBitmap हार्डवेयर त्वरित हैं और GPU पर निष्पादित होते हैं। हालांकि, drawTextOnPath, drawVertices, जटिल क्लिपिंग संचालन त्वरित नहीं हैं — उनके लिए LAYER_TYPE_SOFTWARE का उपयोग करें।
Android Performance Patterns (Google, 2023) के अनुसार, Custom View लैग के मुख्य कारण — onDraw में आवंटन (प्रत्येक फ्रेम में ऑब्जेक्ट बनाना), एक तत्व बदलने पर पूरे View को पुनर्ड्रा करना और स्थिर सामग्री के लिए LayerType.HARDWARE की अनुपस्थिति। इन तीन समस्याओं को ठीक करने से अधिकांश परिदृश्यों में FPS 30 से 60 तक बढ़ जाता है।
| मेथड | उद्देश्य | कॉल आवृत्ति |
|---|---|---|
| onDraw | View सामग्री ड्रा करना | प्रत्येक invalidate() पर |
| onMeasure | View आकार निर्धारित करना | लेआउट बदलने पर |
| onLayout | चाइल्ड Views को स्थापित करना | onMeasure के बाद |
| onTouchEvent | टच हैंडलिंग | प्रत्येक स्पर्श पर |
| onSizeChanged | आकार परिवर्तन पर प्रतिक्रिया | पहले लेआउट और परिवर्तन पर |
अक्सर पूछे जाने वाले प्रश्न
Custom View (Canvas API) उचित है जब अधिकतम कस्टम ड्राइंग प्रदर्शन की आवश्यकता हो (ग्राफ़िक्स, वीडियो संपादक, मैप्स), मौजूदा View-आधारित कोड के साथ एकीकरण या API 21 से नीचे Android संस्करणों का समर्थन। Jetpack Compose अधिकांश नई परियोजनाओं के लिए एक आधुनिक दृष्टिकोण है, जो घोषणात्मक UI का उपयोग करता है और गतिशील इंटरफ़ेस के लिए बेहतर उपयुक्त है।
हाँ, यदि View XML लेआउट में wrap_content का उपयोग करता है। onMeasure के बिना, wrap_content match_parent की तरह व्यवहार करेगा क्योंकि डिफ़ॉल्ट View.onMeasure कार्यान्वयन डिफ़ॉल्ट आकार सेट नहीं करता है। यदि View का हमेशा एक निश्चित आकार या match_parent है, तो onMeasure को ओवरराइड नहीं छोड़ा जा सकता है।
View गुणों (रंग, त्रिज्या, स्थिति) को बदलने के लिए ValueAnimator या ObjectAnimator का उपयोग करें और पुनर्ड्रा के लिए एनिमेशन कॉलबैक में invalidate() कॉल करें। ValueAnimator मुख्य थ्रेड पर चलता है और vsync के साथ सिंक्रनाइज़ है। जटिल एनिमेशन (भौतिकी, कण) के लिए, Choreographer.FrameCallback या Android Animation Framework का उपयोग करें।
onTouchEvent में, उंगलियों की संख्या निर्धारित करने के लिए MotionEvent.getPointerCount() और प्रत्येक उंगली को अद्वितीय ID द्वारा ट्रैक करने के लिए getPointerId(i) का उपयोग करें। ACTION_POINTER_DOWN / ACTION_POINTER_UP — उंगली जोड़ने/हटाने की घटनाएँ। पिंच-टू-ज़ूम के लिए, onTouchEvent के साथ ScaleGestureDetector का उपयोग करें — यह पिंच का पता लगाने को सरल बनाता है।
हाँ, AndroidView के माध्यम से — एक composable फ़ंक्शन जो View-आधारित तत्व को Compose पदानुक्रम में एम्बेड करता है। AndroidView View बनाने के लिए एक फ़ैक्टरी और स्थिति सिंक्रनाइज़ेशन के लिए update कॉलबैक स्वीकार करता है। यह पूर्ण पुनर्लेखन के बिना नई Compose परियोजनाओं में मौजूदा Custom Views का पुन: उपयोग करने की अनुमति देता है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें