Android में Custom View — सार, ड्राइंग और ईवेंट हैंडलिंग

लेखक: IT Sectr प्रकाशित: 2026-07-20 पढ़ने का समय: 9 मिनट

Custom View Android में एक कस्टम इंटरफ़ेस घटक है, जो View क्लास या इसकी उपक्लासेस (Button, TextView, ImageView) से इनहेरिट करके और मुख्य मेथड्स को ओवरराइड करके बनाया जाता है: onDraw ड्राइंग के लिए, onMeasure आकार मापने के लिए और onTouchEvent टच हैंडलिंग के लिए। Google Android Developer Guide (2024) के अनुसार, Custom View का उपयोग तब किया जाता है जब मानक Android SDK घटक आवश्यक व्यवहार या दृश्य प्रदान नहीं करते — उदाहरण के लिए, कस्टम एनिमेशन, गैर-मानक आकार, विशेष चार्ट और गेम तत्व।

मुख्य बिंदु

  • Custom View — View या इसकी उपक्लासेस से इनहेरिट करके onDraw, onMeasure, onTouchEvent को ओवरराइड करके बनाया जाता है।
  • ड्राइंग Canvas API के माध्यम से की जाती है — ज्यामितीय आकार, टेक्स्ट, पथ, Bitmap और एनिमेशन।
  • onMeasure लेआउट पैरामीटर और पैडिंग को ध्यान में रखते हुए View के सही आकार को संभालता है।
  • कस्टम XML एट्रीब्यूट res/values/attrs.xml में घोषित किए जाते हैं और View कंस्ट्रक्टर में पढ़े जाते हैं।
  • onTouchEvent के माध्यम से टच हैंडलिंग जेस्चर सपोर्ट, ड्रैग-एंड-ड्रॉप और मल्टी-टच जोड़ने की अनुमति देती है।

Android में Custom View क्या है?

Custom View एक क्लास है जो android.view.View (या इसकी उपक्लासेस में से एक) से इनहेरिट करती है और कस्टम ड्राइंग, माप और ईवेंट हैंडलिंग तर्क को लागू करने के लिए सिस्टम मेथड्स को ओवरराइड करती है। Custom View अद्वितीय UI घटक बनाने के लिए Android का एक मौलिक तंत्र है।

Android Custom View बनाने के दो दृष्टिकोण प्रदान करता है: View से इनहेरिट करना (onDraw के माध्यम से पूरी तरह से कस्टम ड्राइंग) और मौजूदा View उपक्लास से इनहेरिट करना (उदाहरण के लिए, बेस व्यवहार को बनाए रखते हुए कार्यक्षमता जोड़ने के लिए Button या TextView को ओवरराइड करना)।

बेसिक कंस्ट्रक्टर को Context और AttributeSet स्वीकार करना चाहिए — यह सिस्टम को XML मार्कअप से View बनाने की अनुमति देता है। यदि View केवल कोड से उपयोग किया जाएगा, तो Context वाला कंस्ट्रक्टर पर्याप्त है। स्टाइल वाला तीसरा कंस्ट्रक्टर Android थीम समर्थन के लिए आवश्यक है।

kotlin
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 और onLayout: आकार प्रबंधन

onMeasure वह मेथड है जिसमें View प्राप्त MeasureSpec (पैरेंट बाधाओं) के आधार पर अपने वांछित आयामों की रिपोर्ट करता है। उचित onMeasure कार्यान्वयन के बिना, View की wrap_content के साथ शून्य ऊंचाई हो सकती है या match_parent के साथ पूरी स्क्रीन क्षेत्र घेर सकता है।

MeasureSpec में एक मोड (EXACTLY, AT_MOST, UNSPECIFIED) और एक मान होता है। EXACTLY — पैरेंट ने सटीक आकार सेट किया (match_parent या निश्चित मान)। AT_MOST — पैरेंट ने अधिकतम सेट किया (wrap_content)। UNSPECIFIED — कोई प्रतिबंध नहीं (ScrollView, ListView)।

kotlin
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 और Canvas API: ड्राइंग

onDraw Custom View का हृदय है। यह मेथड Android द्वारा प्रत्येक View पुनर्ड्रा पर बुलाया जाता है। इसे एक Canvas ऑब्जेक्ट पास किया जाता है, जिसके माध्यम से सभी ड्राइंग की जाती है: ज्यामितीय आकार, टेक्स्ट, पथ, Bitmap और एनिमेशन।

Canvas API सभी बुनियादी संचालन के लिए मेथड प्रदान करता है: drawCircle, drawRect, drawLine, drawPath, drawText, drawBitmap, drawArc, drawOval। शैली को कॉन्फ़िगर करने के लिए, Paint का उपयोग किया जाता है — एक ऑब्जेक्ट जो रंग, मोटाई, भरण शैली, फ़ॉन्ट, छाया और प्रभावों को परिभाषित करता है।

kotlin
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() के साथ करें।

attrs.xml में कस्टम XML एट्रीब्यूट

कस्टम एट्रीब्यूट मानक 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 को भेजता है।

xml
<!-- 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() कॉल करना आवश्यक है।

kotlin
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 के साथ टच हैंडलिंग

onTouchEvent वह मेथड है जो View के प्रत्येक स्पर्श पर बुलाया जाता है। यह ईवेंट प्रकार (ACTION_DOWN, ACTION_MOVE, ACTION_UP, ACTION_CANCEL), निर्देशांक, दबाव और उंगलियों की संख्या (मल्टी-टच) के बारे में जानकारी के साथ एक MotionEvent ऑब्जेक्ट प्राप्त करता है।

जटिल जेस्चर (स्वाइप, पिंच, लॉन्ग प्रेस) को संभालने के लिए, onTouchEvent के साथ GestureDetector या ScaleGestureDetector का उपयोग करें। GestureDetector onSingleTapUp, onFling, onLongPress, onDoubleTap और अन्य मानक जेस्चर की पहचान को सरल बनाता है।

kotlin
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 प्रदर्शन अनुकूलन

Custom View प्रदर्शन अड़चन बन सकता है यदि onDraw बार-बार बुलाया जाता है (एनिमेशन, स्क्रॉल) या इसमें भारी संचालन होते हैं। Android कस्टम घटक रेंडरिंग को अनुकूलित करने के लिए कई तंत्र प्रदान करता है।

जटिल ड्राइंग के लिए लेयर प्रकार

View.setLayerType View रेंडरिंग को सॉफ़्टवेयर (LAYER_TYPE_SOFTWARE) या हार्डवेयर (LAYER_TYPE_HARDWARE) लेयर पर स्विच करने की अनुमति देता है। सॉफ़्टवेयर लेयर जटिल Canvas ग्राफ़िक्स के लिए उपयोगी है जो हार्डवेयर त्वरण द्वारा समर्थित नहीं हैं — उदाहरण के लिए, drawTextOnPath या जटिल Path प्रभाव।

केवल आवश्यक क्षेत्र को अमान्य करें

invalidate(Rect) पूरे घटक के बजाय केवल View के निर्दिष्ट क्षेत्र को पुनर्ड्रा करता है। यह बड़े Custom Views (ग्राफ़िक्स, मैप्स, ड्राइंग कैनवस) के लिए महत्वपूर्ण है, जहां प्रत्येक फ्रेम का पूर्ण पुनर्ड्रा FPS गिरावट का कारण बनता है। vsync सिंक्रनाइज़ेशन के लिए postInvalidateOnAnimation() का उपयोग करें।

kotlin
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 तक बढ़ जाता है।

मेथडउद्देश्यकॉल आवृत्ति
onDrawView सामग्री ड्रा करनाप्रत्येक invalidate() पर
onMeasureView आकार निर्धारित करनालेआउट बदलने पर
onLayoutचाइल्ड Views को स्थापित करनाonMeasure के बाद
onTouchEventटच हैंडलिंगप्रत्येक स्पर्श पर
onSizeChangedआकार परिवर्तन पर प्रतिक्रियापहले लेआउट और परिवर्तन पर

अक्सर पूछे जाने वाले प्रश्न

Compose के बजाय Custom View का उपयोग कब करें?

Custom View (Canvas API) उचित है जब अधिकतम कस्टम ड्राइंग प्रदर्शन की आवश्यकता हो (ग्राफ़िक्स, वीडियो संपादक, मैप्स), मौजूदा View-आधारित कोड के साथ एकीकरण या API 21 से नीचे Android संस्करणों का समर्थन। Jetpack Compose अधिकांश नई परियोजनाओं के लिए एक आधुनिक दृष्टिकोण है, जो घोषणात्मक UI का उपयोग करता है और गतिशील इंटरफ़ेस के लिए बेहतर उपयुक्त है।

क्या onMeasure को ओवरराइड करना अनिवार्य है?

हाँ, यदि View XML लेआउट में wrap_content का उपयोग करता है। onMeasure के बिना, wrap_content match_parent की तरह व्यवहार करेगा क्योंकि डिफ़ॉल्ट View.onMeasure कार्यान्वयन डिफ़ॉल्ट आकार सेट नहीं करता है। यदि View का हमेशा एक निश्चित आकार या match_parent है, तो onMeasure को ओवरराइड नहीं छोड़ा जा सकता है।

Custom View को कैसे एनिमेट करें?

View गुणों (रंग, त्रिज्या, स्थिति) को बदलने के लिए ValueAnimator या ObjectAnimator का उपयोग करें और पुनर्ड्रा के लिए एनिमेशन कॉलबैक में invalidate() कॉल करें। ValueAnimator मुख्य थ्रेड पर चलता है और vsync के साथ सिंक्रनाइज़ है। जटिल एनिमेशन (भौतिकी, कण) के लिए, Choreographer.FrameCallback या Android Animation Framework का उपयोग करें।

Custom View में मल्टी-टच कैसे संभालें?

onTouchEvent में, उंगलियों की संख्या निर्धारित करने के लिए MotionEvent.getPointerCount() और प्रत्येक उंगली को अद्वितीय ID द्वारा ट्रैक करने के लिए getPointerId(i) का उपयोग करें। ACTION_POINTER_DOWN / ACTION_POINTER_UP — उंगली जोड़ने/हटाने की घटनाएँ। पिंच-टू-ज़ूम के लिए, onTouchEvent के साथ ScaleGestureDetector का उपयोग करें — यह पिंच का पता लगाने को सरल बनाता है।

क्या Jetpack Compose में Custom View का उपयोग किया जा सकता है?

हाँ, AndroidView के माध्यम से — एक composable फ़ंक्शन जो View-आधारित तत्व को Compose पदानुक्रम में एम्बेड करता है। AndroidView View बनाने के लिए एक फ़ैक्टरी और स्थिति सिंक्रनाइज़ेशन के लिए update कॉलबैक स्वीकार करता है। यह पूर्ण पुनर्लेखन के बिना नई Compose परियोजनाओं में मौजूदा Custom Views का पुन: उपयोग करने की अनुमति देता है।

सारांश

  • Custom View — एक कस्टम Android घटक जो View से इनहेरिट करके कस्टम ड्राइंग और हैंडलिंग के लिए onDraw, onMeasure और onTouchEvent को ओवरराइड करके बनाया जाता है।
  • onDraw और Canvas API — ड्राइंग का आधार: ज्यामितीय आकार, टेक्स्ट, Bitmap, पथ — रंग, शैली और फ़ॉन्ट के लिए Paint के माध्यम से कॉन्फ़िगर किए गए।
  • onMeasure सही wrap_content व्यवहार के लिए महत्वपूर्ण है; आयाम गणना के लिए MeasureSpec (EXACTLY, AT_MOST, UNSPECIFIED) और resolveSize का उपयोग करता है।
  • कस्टम एट्रीब्यूट attrs.xml और TypedArray के माध्यम से Android Studio ऑटोकम्पलीट समर्थन के साथ XML मार्कअप से Custom View को कॉन्फ़िगर करने की अनुमति देते हैं।
  • onTouchEvent GestureDetector के साथ स्पर्श, जेस्चर और मल्टी-टच हैंडलिंग प्रदान करता है, जबकि हिट-टेस्टिंग इंटरैक्शन क्षेत्र निर्धारित करता है।
  • प्रदर्शन: कंस्ट्रक्टर में एक बार ऑब्जेक्ट बनाएं, आंशिक पुनर्ड्रा के लिए invalidate(Rect) और जटिल प्रभावों के लिए LayerType का उपयोग करें।
  • Custom View AndroidView के माध्यम से Jetpack Compose के साथ एकीकृत होता है, जो नई Compose परियोजनाओं में तैयार घटकों का पुन: उपयोग करने की अनुमति देता है।

हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे

IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।

परियोजना पर चर्चा करें

यह भी पढ़ें