कस्टम व्यू बनाना

यह कोडलैब, Kotlin में ऐडवांस Android कोर्स का हिस्सा है. अगर इस कोर्स के कोडलैब को क्रम से पूरा किया जाता है, तो आपको सबसे ज़्यादा फ़ायदा मिलेगा. हालांकि, ऐसा करना ज़रूरी नहीं है. कोर्स के सभी कोडलब, Advanced Android in Kotlin कोडलब के लैंडिंग पेज पर दिए गए हैं.

परिचय

Android, View की कई सबक्लास उपलब्ध कराता है. जैसे, Button, TextView, EditText, ImageView, CheckBox या RadioButton. इन सबक्लास का इस्तेमाल करके, ऐसा यूज़र इंटरफ़ेस (यूआई) बनाया जा सकता है जिससे उपयोगकर्ता इंटरैक्ट कर सकें और आपके ऐप्लिकेशन में जानकारी दिख सके. अगर इनमें से कोई भी View सबक्लास आपकी ज़रूरतों को पूरा नहीं करती है, तो View सबक्लास बनाई जा सकती है. इसे कस्टम व्यू कहा जाता है.

कस्टम व्यू बनाने के लिए, मौजूदा View सबक्लास (जैसे कि Button या EditText) को बढ़ाया जा सकता है. इसके अलावा, View की अपनी सबक्लास बनाई जा सकती है. View को सीधे तौर पर बढ़ाकर, किसी भी साइज़ और शेप का इंटरैक्टिव यूज़र इंटरफ़ेस (यूआई) एलिमेंट बनाया जा सकता है. इसके लिए, View को ड्रॉ करने के लिए onDraw() तरीके को बदलें.

कस्टम व्यू बनाने के बाद, उसे अपनी गतिविधि के लेआउट में जोड़ा जा सकता है. इसे उसी तरह जोड़ा जाता है जिस तरह TextView या Button को जोड़ा जाता है.

इस लेख में, View को बढ़ाकर, कस्टम व्यू बनाने का तरीका बताया गया है.

आपको पहले से क्या पता होना चाहिए

  • Android Studio का इस्तेमाल करके, गतिविधि वाला ऐप्लिकेशन बनाने और उसे चलाने का तरीका.

आपको क्या सीखने को मिलेगा

  • कस्टम व्यू बनाने के लिए, View को बढ़ाने का तरीका.
  • सर्कुलर शेप में कस्टम व्यू बनाने का तरीका.
  • कस्टम व्यू के साथ उपयोगकर्ता के इंटरैक्शन को मैनेज करने के लिए, लिसनर का इस्तेमाल करने का तरीका.
  • लेआउट में कस्टम व्यू का इस्तेमाल कैसे करें.

आपको क्या करना होगा

  • कस्टम व्यू बनाने के लिए, View को बड़ा करें.
  • ड्रॉइंग और पेंटिंग की वैल्यू के साथ कस्टम व्यू को शुरू करें.
  • व्यू बनाने के लिए, onDraw() को बदलें.
  • कस्टम व्यू के व्यवहार को तय करने के लिए, लिसनर का इस्तेमाल करें.
  • कस्टम व्यू को लेआउट में जोड़ें.

CustomFanController ऐप्लिकेशन, View क्लास को बढ़ाकर कस्टम व्यू सबक्लास बनाने का तरीका दिखाता है. नई सबक्लास को DialView कहा जाता है.

ऐप्लिकेशन में, गोल आकार का यूज़र इंटरफ़ेस (यूआई) एलिमेंट दिखता है. यह फ़ैन को कंट्रोल करने वाले फ़िज़िकल बटन जैसा दिखता है. इसमें फ़ैन को बंद करने (0), कम (1), मीडियम (2), और तेज़ (3) पर चलाने की सेटिंग होती है. जब उपयोगकर्ता व्यू पर टैप करता है, तो चुनने का इंडिकेटर अगली पोज़िशन पर चला जाता है: 0-1-2-3 और फिर वापस 0 पर आ जाता है. इसके अलावा, अगर पंखे की स्पीड 1 या इससे ज़्यादा पर सेट है, तो व्यू के गोलाकार हिस्से का बैकग्राउंड रंग स्लेटी से हरा हो जाता है. इससे पता चलता है कि पंखा चालू है.

व्यू, किसी ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) के बुनियादी बिल्डिंग ब्लॉक होते हैं. View क्लास कई सबक्लास उपलब्ध कराता है. इन्हें यूज़र इंटरफ़ेस (यूआई) विजेट कहा जाता है. ये Android ऐप्लिकेशन के यूज़र इंटरफ़ेस की कई ज़रूरतों को पूरा करते हैं.

यूज़र इंटरफ़ेस (यूआई) के बिल्डिंग ब्लॉक, जैसे कि Button और TextView, ऐसी सबक्लास हैं जो View क्लास को बढ़ाती हैं. समय और डेवलपमेंट की मेहनत बचाने के लिए, इनमें से किसी एक View सबक्लास को बढ़ाया जा सकता है. कस्टम व्यू, अपने पैरंट व्यू के लुक और व्यवहार को इनहेरिट करता है. हालांकि, आपके पास लुक या व्यवहार के उस पहलू को बदलने का विकल्प होता है जिसे आपको बदलना है. उदाहरण के लिए, अगर कस्टम व्यू बनाने के लिए EditText को बढ़ाया जाता है, तो व्यू, EditText व्यू की तरह ही काम करता है. हालांकि, इसे इस तरह से भी पसंद के मुताबिक बनाया जा सकता है कि यह, उदाहरण के लिए, X बटन दिखाए. यह बटन, टेक्स्ट एंट्री फ़ील्ड से टेक्स्ट मिटाता है.

अपनी पसंद के मुताबिक व्यू पाने के लिए, किसी भी View सबक्लास, जैसे कि EditText को बढ़ाया जा सकता है. वह सबक्लास चुनें जो आपके काम के सबसे ज़्यादा करीब हो. इसके बाद, कस्टम व्यू का इस्तेमाल एक या उससे ज़्यादा लेआउट में, किसी अन्य View सबक्लास की तरह किया जा सकता है. इसके लिए, इसे एट्रिब्यूट वाले एक्सएमएल एलिमेंट के तौर पर इस्तेमाल करें.

शुरुआत से अपना कस्टम व्यू बनाने के लिए, View क्लास को बढ़ाएं. आपका कोड, व्यू की परफ़ॉर्मेंस और काम करने के तरीके को तय करने के लिए, View तरीकों को बदल देता है. कस्टम व्यू बनाने के लिए, यह ज़रूरी है कि आप स्क्रीन पर किसी भी साइज़ और शेप के पूरे यूज़र इंटरफ़ेस (यूआई) एलिमेंट को ड्रॉ करें. अगर किसी मौजूदा व्यू, जैसे कि Button को सबक्लास किया जाता है, तो वह क्लास आपके लिए ड्रॉइंग को मैनेज करती है. (आपको इस कोडलैब में बाद में ड्राइंग के बारे में ज़्यादा जानकारी मिलेगी.)

कस्टम व्यू बनाने के लिए, यह सामान्य तरीका अपनाएं:

  • View को बढ़ाने वाली कस्टम व्यू क्लास बनाएं या View की सबक्लास (जैसे कि Button या EditText) को बढ़ाएं.
  • अगर आपको किसी मौजूदा View सबक्लास को बढ़ाना है, तो सिर्फ़ उस व्यवहार या दिखने के तरीके को बदलें जिसे आपको बदलना है.
  • अगर आपको View क्लास को बढ़ाना है, तो कस्टम व्यू का आकार बनाएं. साथ ही, नई क्लास में View के onDraw() और onMeasure() जैसे तरीकों को बदलकर, कस्टम व्यू की स्टाइल को कंट्रोल करें.
  • उपयोगकर्ता के इंटरैक्शन का जवाब देने के लिए कोड जोड़ें. साथ ही, अगर ज़रूरी हो, तो कस्टम व्यू को फिर से बनाएं.
  • अपनी ऐक्टिविटी के एक्सएमएल लेआउट में, कस्टम व्यू क्लास को यूज़र इंटरफ़ेस (यूआई) विजेट के तौर पर इस्तेमाल करें. अलग-अलग लेआउट में व्यू को पसंद के मुताबिक बनाने के लिए, व्यू के लिए कस्टम एट्रिब्यूट भी तय किए जा सकते हैं.

इस टास्क में आपको:

  • कस्टम व्यू के लिए, ImageView को कुछ समय के लिए प्लेसहोल्डर के तौर पर इस्तेमाल करके कोई ऐप्लिकेशन बनाएं.
  • कस्टम व्यू बनाने के लिए, View को बड़ा करें.
  • ड्रॉइंग और पेंटिंग की वैल्यू के साथ कस्टम व्यू को शुरू करें.

पहला चरण: ImageView प्लेसहोल्डर वाला ऐप्लिकेशन बनाना

  1. Empty Activity टेंप्लेट का इस्तेमाल करके, CustomFanController टाइटल वाला Kotlin ऐप्लिकेशन बनाएं. पक्का करें कि पैकेज का नाम com.example.android.customfancontroller हो.
  2. एक्सएमएल कोड में बदलाव करने के लिए, टेक्स्ट टैब में activity_main.xml खोलें.
  3. मौजूदा TextView को इस कोड से बदलें. यह टेक्स्ट, कस्टम व्यू के लिए गतिविधि में लेबल के तौर पर काम करता है.
<TextView
       android:id="@+id/customViewLabel"
       android:textAppearance="@style/Base.TextAppearance.AppCompat.Display3"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:padding="16dp"
       android:textColor="@android:color/black"
       android:layout_marginStart="8dp"
       android:layout_marginEnd="8dp"
       android:layout_marginTop="24dp"
       android:text="Fan Control"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       app:layout_constraintTop_toTopOf="parent"/>
  1. इस ImageView एलिमेंट को लेआउट में जोड़ें. यह उस कस्टम व्यू के लिए प्लेसहोल्डर है जिसे आपको इस कोडलैब में बनाना है.
<ImageView
       android:id="@+id/dialView"
       android:layout_width="200dp"
       android:layout_height="200dp"
       android:background="@android:color/darker_gray"
       app:layout_constraintTop_toBottomOf="@+id/customViewLabel"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       android:layout_marginLeft="8dp"
       android:layout_marginRight="8dp"
       android:layout_marginTop="8dp"/>
  1. दोनों यूज़र इंटरफ़ेस (यूआई) एलिमेंट में स्ट्रिंग और डाइमेंशन रिसॉर्स एक्सट्रैक्ट करें.
  2. डिज़ाइन टैब पर क्लिक करें. लेआउट ऐसा दिखना चाहिए:

दूसरा चरण. कस्टम व्यू क्लास बनाना

  1. DialView नाम की नई Kotlin क्लास बनाएं.
  2. View को बढ़ाने के लिए, क्लास की परिभाषा में बदलाव करें. निर्देश मिलने पर, android.view.View इंपोर्ट करें.
  3. View पर क्लिक करें. इसके बाद, लाल रंग के बल्ब पर क्लिक करें. '@JvmOverloads' का इस्तेमाल करके, Android व्यू कंस्ट्रक्टर जोड़ें को चुनें. Android Studio, View क्लास से कंस्ट्रक्टर जोड़ता है. @JvmOverloads एनोटेशन, Kotlin कंपाइलर को इस फ़ंक्शन के लिए ओवरलोड जनरेट करने का निर्देश देता है. ये ओवरलोड, डिफ़ॉल्ट पैरामीटर वैल्यू को बदल देते हैं.
class DialView @JvmOverloads constructor(
   context: Context,
   attrs: AttributeSet? = null,
   defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
  1. DialView क्लास की परिभाषा के ऊपर, इंपोर्ट के ठीक नीचे, उपलब्ध पंखे की स्पीड दिखाने के लिए टॉप-लेवल enum जोड़ें. ध्यान दें कि यह enum, Int टाइप का है, क्योंकि वैल्यू असल स्ट्रिंग के बजाय स्ट्रिंग रिसॉर्स हैं. Android Studio, इन वैल्यू में मौजूद स्ट्रिंग रिसॉर्स के लिए गड़बड़ियां दिखाएगा. हालांकि, आपको बाद के चरण में इन्हें ठीक करना होगा.
private enum class FanSpeed(val label: Int) {
   OFF(R.string.fan_off),
   LOW(R.string.fan_low),
   MEDIUM(R.string.fan_medium),
   HIGH(R.string.fan_high);
}
  1. enum के नीचे, ये कॉन्सटेंट जोड़ें. इनका इस्तेमाल, डायल इंडिकेटर और लेबल बनाने के लिए किया जाएगा.
private const val RADIUS_OFFSET_LABEL = 30      
private const val RADIUS_OFFSET_INDICATOR = -35
  1. DialView क्लास में, कस्टम व्यू बनाने के लिए ज़रूरी वैरिएबल तय करें. अगर कहा जाए, तो android.graphics.PointF इंपोर्ट करें.
private var radius = 0.0f                   // Radius of the circle.
private var fanSpeed = FanSpeed.OFF         // The active selection.
// position variable which will be used to draw label and indicator circle position
private val pointPosition: PointF = PointF(0.0f, 0.0f)
  • radius, सर्कल का मौजूदा दायरा है. यह वैल्यू तब सेट होती है, जब व्यू को स्क्रीन पर दिखाया जाता है.
  • fanSpeed पंखे की मौजूदा स्पीड है. यह FanSpeed इन्यूमरेशन में मौजूद वैल्यू में से एक है. डिफ़ॉल्ट रूप से, यह वैल्यू OFF होती है.
  • Finally postPosition एक X,Y पॉइंट है. इसका इस्तेमाल, स्क्रीन पर व्यू के कई एलिमेंट बनाने के लिए किया जाएगा.

इन वैल्यू को व्यू के रेंडर होने के समय के बजाय, यहां बनाया और शुरू किया जाता है. इससे यह पक्का किया जा सकता है कि रेंडरिंग का प्रोसेस तेज़ी से हो.

  1. साथ ही, DialView क्लास की परिभाषा में, कुछ बुनियादी स्टाइल के साथ Paint ऑब्जेक्ट को शुरू करें. अनुरोध किए जाने पर, android.graphics.Paint और android.graphics.Typeface इंपोर्ट करें. पहले की तरह, यहां वैरिएबल के साथ-साथ इन स्टाइल को भी शुरू किया गया है, ताकि ड्रॉइंग की प्रोसेस को तेज़ी से पूरा किया जा सके.
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
   style = Paint.Style.FILL
   textAlign = Paint.Align.CENTER
   textSize = 55.0f
   typeface = Typeface.create( "", Typeface.BOLD)
}
  1. res/values/strings.xml खोलें और पंखे की स्पीड के लिए स्ट्रिंग रिसॉर्स जोड़ें:
<string name="fan_off">off</string>
<string name="fan_low">1</string>
<string name="fan_medium">2</string>
<string name="fan_high">3</string>

कस्टम व्यू बनाने के बाद, आपको उसे ड्रा करने की सुविधा मिलनी चाहिए. जब किसी View सबक्लास, जैसे कि EditText को बढ़ाया जाता है, तो वह सबक्लास व्यू की बनावट और एट्रिब्यूट तय करता है. साथ ही, स्क्रीन पर खुद को दिखाता है. इसलिए, आपको व्यू बनाने के लिए कोड लिखने की ज़रूरत नहीं होती. इसके बजाय, अपने व्यू को पसंद के मुताबिक बनाने के लिए, पैरंट के तरीकों को बदला जा सकता है.

अगर आपको स्क्रैच से अपना व्यू बनाना है (View को बढ़ाकर), तो स्क्रीन के रीफ़्रेश होने पर, पूरे व्यू को हर बार ड्रॉ करने की ज़िम्मेदारी आपकी होगी. साथ ही, ड्रॉ करने वाली View के तरीकों को बदलने की ज़िम्मेदारी भी आपकी होगी. View तक फैले कस्टम व्यू को सही तरीके से बनाने के लिए, आपको ये काम करने होंगे:

  • onSizeChanged() तरीके को बदलकर, व्यू के पहली बार दिखने पर उसके साइज़ का हिसाब लगाएं. साथ ही, व्यू के साइज़ में बदलाव होने पर भी ऐसा करें.
  • onDraw() तरीके को बदलकर, कस्टम व्यू बनाएं. इसके लिए, Paint ऑब्जेक्ट से स्टाइल किए गए Canvas ऑब्जेक्ट का इस्तेमाल करें.
  • जब उपयोगकर्ता के क्लिक करने पर व्यू में बदलाव होता है, तब invalidate() तरीके को कॉल करें. इससे पूरे व्यू को अमान्य कर दिया जाता है. इस वजह से, व्यू को फिर से बनाने के लिए onDraw() को कॉल करना पड़ता है.

onDraw() तरीके को हर बार स्क्रीन रीफ़्रेश होने पर कॉल किया जाता है. ऐसा एक सेकंड में कई बार हो सकता है. परफ़ॉर्मेंस को बेहतर बनाने और विज़ुअल गड़बड़ियों से बचने के लिए, आपको onDraw() में कम से कम काम करना चाहिए. खास तौर पर, onDraw() में मेमोरी असाइन न करें. ऐसा इसलिए, क्योंकि मेमोरी असाइन करने से गार्बेज कलेक्शन हो सकता है. इससे विज़ुअल स्टटरिंग की समस्या हो सकती है.

Canvas और Paint क्लास में, ड्राइंग के कई काम के शॉर्टकट उपलब्ध होते हैं:

  • drawText() का इस्तेमाल करके टेक्स्ट बनाएं. setTypeface() को कॉल करके टाइपफ़ेस और setColor() को कॉल करके टेक्स्ट का रंग तय करें.
  • drawRect(), drawOval(), और drawArc() का इस्तेमाल करके, सामान्य आकृतियां बनाएं. setStyle() को कॉल करके, यह बदलें कि शेप में रंग भरा गया है, आउटलाइन बनाई गई है या दोनों काम किए गए हैं.
  • drawBitmap() का इस्तेमाल करके बिटमैप बनाएं.

आपको बाद के कोडलैब में Canvas और Paint के बारे में ज़्यादा जानकारी मिलेगी. Android, व्यू को कैसे ड्रॉ करता है, इस बारे में ज़्यादा जानने के लिए Android, व्यू को कैसे ड्रॉ करता है लेख पढ़ें.

इस टास्क में, आपको onSizeChanged() और onDraw() तरीकों का इस्तेमाल करके, स्क्रीन पर फ़ैन कंट्रोलर का कस्टम व्यू बनाना होगा. इसमें डायल, मौजूदा पोज़िशन इंडिकेटर, और इंडिकेटर लेबल शामिल हैं. आपको एक हेल्पर मेथड, computeXYForSpeed(), भी बनाना होगा. इससे डायल पर इंडिकेटर लेबल की मौजूदा X,Y पोज़िशन का हिसाब लगाया जा सकेगा.

पहला चरण. पोजीशन कैलकुलेट करना और व्यू बनाना

  1. कस्टम व्यू के डायल का साइज़ कैलकुलेट करने के लिए, DialView क्लास में, इनिशियलाइज़ेशन के नीचे, View क्लास से onSizeChanged() तरीके को बदलें. kotlin को इंपोर्ट करें.math.min का अनुरोध करने पर.

    लेआउट के बड़ा होने पर, onSizeChanged() तरीके को तब कॉल किया जाता है, जब व्यू का साइज़ बदलता है. इसमें पहली बार व्यू के ड्रॉ होने का समय भी शामिल है. onSizeChanged() को ओवरराइड करके, अपनी कस्टम व्यू की साइज़ से जुड़ी पोज़िशन, डाइमेंशन, और अन्य वैल्यू कैलकुलेट करें. ऐसा हर बार ड्रॉ करने के बजाय करें. इस मामले में, डायल के सर्कल एलिमेंट के मौजूदा रेडियस का हिसाब लगाने के लिए onSizeChanged() का इस्तेमाल किया जाता है.
override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
   radius = (min(width, height) / 2.0 * 0.8).toFloat()
}
  1. नीचे दिए गए onSizeChanged() कोड को जोड़कर, PointF क्लास के लिए computeXYForSpeed() एक्सटेंशन फ़ंक्शन तय करें. अनुरोध किए जाने पर, kotlin.math.cos और kotlin.math.sin इंपोर्ट करें. PointF क्लास पर मौजूद यह एक्सटेंशन फ़ंक्शन, टेक्स्ट लेबल और मौजूदा इंडिकेटर (0, 1, 2 या 3) के लिए स्क्रीन पर X और Y कोऑर्डिनेट का हिसाब लगाता है. इसके लिए, डायल की मौजूदा FanSpeed पोज़िशन और रेडियस का इस्तेमाल किया जाता है. इसका इस्तेमाल onDraw(). में किया जाएगा
private fun PointF.computeXYForSpeed(pos: FanSpeed, radius: Float) {
   // Angles are in radians.
   val startAngle = Math.PI * (9 / 8.0)   
   val angle = startAngle + pos.ordinal * (Math.PI / 4)
   x = (radius * cos(angle)).toFloat() + width / 2
   y = (radius * sin(angle)).toFloat() + height / 2
}
  1. onDraw() तरीके को ओवरराइड करें, ताकि Canvas और Paint क्लास की मदद से, स्क्रीन पर व्यू रेंडर किया जा सके. अनुरोध किए जाने पर, android.graphics.Canvas इंपोर्ट करें. यह स्केलेटन ओवरराइड है:
override fun onDraw(canvas: Canvas) {
   super.onDraw(canvas)
   
}
  1. onDraw() के अंदर, इस लाइन को जोड़कर पेंट का रंग स्लेटी (Color.GRAY) या हरा (Color.GREEN) पर सेट करें. यह इस बात पर निर्भर करता है कि पंखे की स्पीड OFF है या कोई अन्य वैल्यू. अनुरोध किए जाने पर, android.graphics.Color इंपोर्ट करें.
// Set dial background color to green if selection not off.
paint.color = if (fanSpeed == FanSpeed.OFF) Color.GRAY else Color.GREEN
  1. डायल के लिए सर्कल बनाने के लिए, इस कोड को जोड़ें. इसके लिए, drawCircle() तरीके का इस्तेमाल करें. इस तरीके में, सर्कल का सेंटर, सर्कल की त्रिज्या, और मौजूदा पेंट का रंग पता करने के लिए, मौजूदा व्यू की चौड़ाई और ऊंचाई का इस्तेमाल किया जाता है. width और height प्रॉपर्टी, View सुपरक्लास की सदस्य हैं. ये व्यू के मौजूदा डाइमेंशन दिखाती हैं.
// Draw the dial.
canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, paint)
  1. पंखे की स्पीड दिखाने वाले इंडिकेटर मार्क के लिए, छोटा सर्कल बनाने के लिए यह कोड जोड़ें. इसके लिए, drawCircle() तरीके का इस्तेमाल करें इस हिस्से में PointF का इस्तेमाल किया गया है.computeXYforSpeed() एक्सटेंशन का यह तरीका, पंखे की मौजूदा रफ़्तार के आधार पर इंडिकेटर सेंटर के X,Y कोऑर्डिनेट का हिसाब लगाता है.
// Draw the indicator circle.
val markerRadius = radius + RADIUS_OFFSET_INDICATOR
pointPosition.computeXYForSpeed(fanSpeed, markerRadius)
paint.color = Color.BLACK
canvas.drawCircle(pointPosition.x, pointPosition.y, radius/12, paint)
  1. आखिर में, डायल के चारों ओर सही जगहों पर पंखे की स्पीड के लेबल (0, 1, 2, 3) बनाएं. इस तरीके का यह हिस्सा, हर लेबल के लिए पोज़िशन पाने के लिए PointF.computeXYForSpeed() को फिर से कॉल करता है. साथ ही, हर बार pointPosition ऑब्जेक्ट का फिर से इस्तेमाल करता है, ताकि आवंटन से बचा जा सके. लेबल बनाने के लिए, drawText() का इस्तेमाल करें.
// Draw the text labels.
val labelRadius = radius + RADIUS_OFFSET_LABEL
for (i in FanSpeed.values()) {
   pointPosition.computeXYForSpeed(i, labelRadius)
   val label = resources.getString(i.label)
   canvas.drawText(label, pointPosition.x, pointPosition.y, paint)
}

onDraw() तरीका पूरा होने पर ऐसा दिखता है:

override fun onDraw(canvas: Canvas) {
   super.onDraw(canvas)
   // Set dial background color to green if selection not off.
   paint.color = if (fanSpeed == FanSpeed.OFF) Color.GRAY else Color.GREEN
   // Draw the dial.
   canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, paint)
   // Draw the indicator circle.
   val markerRadius = radius + RADIUS_OFFSET_INDICATOR
   pointPosition.computeXYForSpeed(fanSpeed, markerRadius)
   paint.color = Color.BLACK
   canvas.drawCircle(pointPosition.x, pointPosition.y, radius/12, paint)
   // Draw the text labels.
   val labelRadius = radius + RADIUS_OFFSET_LABEL
   for (i in FanSpeed.values()) {
       pointPosition.computeXYForSpeed(i, labelRadius)
       val label = resources.getString(i.label)
       canvas.drawText(label, pointPosition.x, pointPosition.y, paint)
   }
}

दूसरा चरण. लेआउट में व्यू जोड़ना

किसी ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में कस्टम व्यू जोड़ने के लिए, उसे ऐक्टिविटी के एक्सएमएल लेआउट में एक एलिमेंट के तौर पर तय करें. एक्सएमएल एलिमेंट एट्रिब्यूट का इस्तेमाल करके, इसके दिखने के तरीके और काम करने के तरीके को कंट्रोल करें. ठीक वैसे ही जैसे किसी अन्य यूज़र इंटरफ़ेस (यूआई) एलिमेंट के लिए किया जाता है.

  1. activity_main.xml में, dialView के लिए ImageView टैग को com.example.android.customfancontroller.DialView में बदलें और android:background एट्रिब्यूट को मिटाएं. DialView और ओरिजनल ImageView, दोनों View क्लास से स्टैंडर्ड एट्रिब्यूट इनहेरिट करते हैं. इसलिए, किसी भी दूसरे एट्रिब्यूट को बदलने की ज़रूरत नहीं है. नया DialView एलिमेंट ऐसा दिखता है:
<com.example.android.customfancontroller.DialView
       android:id="@+id/dialView"
       android:layout_width="@dimen/fan_dimen"
       android:layout_height="@dimen/fan_dimen"
       app:layout_constraintTop_toBottomOf="@+id/customViewLabel"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       android:layout_marginLeft="@dimen/default_margin"
       android:layout_marginRight="@dimen/default_margin"
       android:layout_marginTop="@dimen/default_margin" />
  1. ऐप्लिकेशन चलाएं. आपको गतिविधि में पंखे को कंट्रोल करने का विकल्प दिखेगा.

आखिरी काम यह है कि उपयोगकर्ता के व्यू पर टैप करने पर कार्रवाई करने के लिए, कस्टम व्यू को चालू करें. हर बार टैप करने पर, चुनने का इंडिकेटर अगली पोज़िशन पर जाना चाहिए: बंद-1-2-3 और फिर से बंद. साथ ही, अगर चुना गया विकल्प 1 या उससे ज़्यादा है, तो बैकग्राउंड को ग्रे से हरे रंग में बदलें. इससे पता चलता है कि पंखे की स्पीड चालू है.

कस्टम व्यू पर क्लिक करने की सुविधा चालू करने के लिए:

  • व्यू की isClickable प्रॉपर्टी को true पर सेट करें. इससे आपकी कस्टम व्यू सुविधा, क्लिक का जवाब दे पाती है.
  • व्यू पर क्लिक करने पर कार्रवाइयां करने के लिए, View क्लास के performClick() को लागू करें.
  • invalidate() तरीके को कॉल करें. इससे Android सिस्टम को व्यू को फिर से रेंडर करने के लिए, onDraw() तरीके को कॉल करने का निर्देश मिलता है.

आम तौर पर, स्टैंडर्ड Android व्यू में, उपयोगकर्ता के उस व्यू पर क्लिक करने पर कोई कार्रवाई करने के लिए, OnClickListener() को लागू किया जाता है. कस्टम व्यू के लिए, View क्लास के performClick() तरीके को लागू करें. इसके बाद, super को कॉल करें.performClick(). डिफ़ॉल्ट performClick() तरीके से भी onClickListener() को कॉल किया जाता है. इसलिए, performClick() में अपनी कार्रवाइयां जोड़ी जा सकती हैं. साथ ही, onClickListener() को आपके या अन्य डेवलपर के लिए उपलब्ध कराया जा सकता है, ताकि वे कस्टम व्यू को और ज़्यादा पसंद के मुताबिक बना सकें.

  1. DialView.kt में, FanSpeed इन्यूमरेशन के अंदर, एक्सटेंशन फ़ंक्शन next() जोड़ें. यह फ़ंक्शन, पंखे की मौजूदा स्पीड को सूची में दी गई अगली स्पीड में बदलता है. जैसे, OFF से LOW, MEDIUM, और HIGH पर ले जाता है. इसके बाद, वापस OFF पर ले जाता है. अब पूरा इन्यूमरेशन इस तरह दिखता है:
private enum class FanSpeed(val label: Int) {
   OFF(R.string.fan_off),
   LOW(R.string.fan_low),
   MEDIUM(R.string.fan_medium),
   HIGH(R.string.fan_high);

   fun next() = when (this) {
       OFF -> LOW
       LOW -> MEDIUM
       MEDIUM -> HIGH
       HIGH -> OFF
   }
}
  1. DialView क्लास में, onSizeChanged() तरीके से ठीक पहले, init() ब्लॉक जोड़ें. व्यू की isClickable प्रॉपर्टी को सही पर सेट करने से, व्यू को उपयोगकर्ता के इनपुट स्वीकार करने की अनुमति मिलती है.
init {
   isClickable = true
}
  1. नीचे दिए गए कोड का इस्तेमाल करके, init(), में performClick() तरीके को बदलें.
override fun performClick(): Boolean {
   if (super.performClick()) return true

   fanSpeed = fanSpeed.next()
   contentDescription = resources.getString(fanSpeed.label)
  
   invalidate()
   return true
}

super को किया गया कॉल.performClick() सबसे पहले होना चाहिए. इससे सुलभता इवेंट के साथ-साथ कॉल onClickListener() भी चालू हो जाते हैं.

अगली दो लाइनों में, next() तरीके का इस्तेमाल करके पंखे की स्पीड को बढ़ाया जाता है. साथ ही, व्यू के कॉन्टेंट के ब्यौरे को स्ट्रिंग रिसॉर्स पर सेट किया जाता है. यह स्ट्रिंग रिसॉर्स, पंखे की मौजूदा स्पीड (बंद, 1, 2 या 3) को दिखाता है.

आखिर में, invalidate() तरीके से पूरे व्यू को अमान्य कर दिया जाता है. इससे onDraw() को व्यू फिर से बनाने के लिए कॉल करना पड़ता है. अगर किसी वजह से आपके कस्टम व्यू में कोई बदलाव होता है, तो invalidate(). को कॉल करें. बदलाव की वजहों में उपयोगकर्ता का इंटरैक्शन भी शामिल है.

  1. ऐप्लिकेशन चलाएं. इंडिकेटर को बंद से 1 पर ले जाने के लिए, DialView एलिमेंट पर टैप करें. डायल का रंग हरा हो जाना चाहिए. हर बार टैप करने पर, इंडिकेटर को अगली जगह पर जाना चाहिए. जब इंडिकेटर बंद हो जाए, तो डायल का रंग फिर से स्लेटी हो जाना चाहिए.

इस उदाहरण में, कस्टम व्यू के साथ कस्टम एट्रिब्यूट इस्तेमाल करने का तरीका बताया गया है. आपने DialView क्लास के लिए कस्टम एट्रिब्यूट तय किए हैं. इनमें हर फ़ैन डायल पोज़िशन के लिए अलग-अलग रंग दिए गए हैं.

  1. res/values/attrs.xml बनाएं और खोलें.
  2. <resources> के अंदर, <declare-styleable> रिसॉर्स एलिमेंट जोड़ें.
  3. <declare-styleable> रिसॉर्स एलिमेंट में, तीन attr एलिमेंट जोड़ें. हर एट्रिब्यूट के लिए एक एलिमेंट जोड़ें. साथ ही, name और format एट्रिब्यूट भी जोड़ें. format एक तरह का टाइप होता है. इस मामले में, यह color है.
<?xml version="1.0" encoding="utf-8"?>
<resources>
       <declare-styleable name="DialView">
           <attr name="fanColor1" format="color" />
           <attr name="fanColor2" format="color" />
           <attr name="fanColor3" format="color" />
       </declare-styleable>
</resources>
  1. activity_main.xml लेआउट फ़ाइल खोलें.
  2. DialView में, fanColor1, fanColor2, और fanColor3 के लिए एट्रिब्यूट जोड़ें. साथ ही, उनकी वैल्यू को यहां दिखाए गए रंगों पर सेट करें. कस्टम एट्रिब्यूट के लिए, android: के बजाय app: को प्रीफ़ेस के तौर पर इस्तेमाल करें. जैसे, app:fanColor1. ऐसा इसलिए, क्योंकि आपके कस्टम एट्रिब्यूट, android नेमस्पेस के बजाय schemas.android.com/apk/res/your_app_package_name नेमस्पेस से जुड़े हैं.
app:fanColor1="#FFEB3B"
app:fanColor2="#CDDC39"
app:fanColor3="#009688"

अपनी DialView क्लास में एट्रिब्यूट इस्तेमाल करने के लिए, आपको उन्हें वापस पाना होगा. इन्हें AttributeSet में सेव किया जाता है. अगर यह मौजूद है, तो क्लास बनाने पर इसे आपकी क्लास को सौंप दिया जाता है. init में एट्रिब्यूट वापस पाए जाते हैं. साथ ही, एट्रिब्यूट की वैल्यू को कैश मेमोरी में सेव करने के लिए, लोकल वैरिएबल असाइन किए जाते हैं.

  1. DialView.kt क्लास फ़ाइल खोलें.
  2. DialView के अंदर, एट्रिब्यूट की वैल्यू को कैश मेमोरी में सेव करने के लिए वैरिएबल तय करें.
private var fanSpeedLowColor = 0
private var fanSpeedMediumColor = 0
private var fanSeedMaxColor = 0
  1. init ब्लॉक में, withStyledAttributes एक्सटेंशन फ़ंक्शन का इस्तेमाल करके यह कोड जोड़ें. आपको एट्रिब्यूट और व्यू उपलब्ध कराने होते हैं. साथ ही, आपको स्थानीय वैरिएबल सेट करने होते हैं. withStyledAttributes को इंपोर्ट करने पर, getColor() फ़ंक्शन भी इंपोर्ट हो जाएगा.
context.withStyledAttributes(attrs, R.styleable.DialView) {
   fanSpeedLowColor = getColor(R.styleable.DialView_fanColor1, 0)
   fanSpeedMediumColor = getColor(R.styleable.DialView_fanColor2, 0)
   fanSeedMaxColor = getColor(R.styleable.DialView_fanColor3, 0)
}
  1. onDraw() में लोकल वैरिएबल का इस्तेमाल करके, पंखे की मौजूदा स्पीड के हिसाब से डायल का रंग सेट करें. पेंट का रंग सेट करने वाली लाइन (paint.color = if (fanSpeed == FanSpeed.OFF) Color.GRAY else Color.GREEN) को नीचे दिए गए कोड से बदलें.
paint.color = when (fanSpeed) {
   FanSpeed.OFF -> Color.GRAY
   FanSpeed.LOW -> fanSpeedLowColor
   FanSpeed.MEDIUM -> fanSpeedMediumColor
   FanSpeed.HIGH -> fanSeedMaxColor
} as Int
  1. अपने ऐप्लिकेशन को चलाएं, डायल पर क्लिक करें. साथ ही, हर पोज़िशन के लिए रंग की सेटिंग अलग-अलग होनी चाहिए, जैसा कि यहां दिखाया गया है.

कस्टम व्यू एट्रिब्यूट के बारे में ज़्यादा जानने के लिए, व्यू क्लास बनाना लेख पढ़ें.

सुलभता, डिज़ाइन, लागू करने, और टेस्टिंग के तरीकों का एक सेट है. इससे आपके ऐप्लिकेशन को सभी लोग इस्तेमाल कर पाते हैं. इनमें दिव्यांग लोग भी शामिल हैं.

सामान्य तौर पर, किसी व्यक्ति को Android डिवाइस इस्तेमाल करने में इन वजहों से परेशानी हो सकती है: दृष्टिहीनता, कम दिखाई देना, रंग की पहचान न कर पाना, बहरापन या सुनने की क्षमता कम होना, और चलने-फिरने में दिक्कत होना. सुलभता को ध्यान में रखकर ऐप्लिकेशन डेवलप करने से, न सिर्फ़ इन अक्षमताओं वाले उपयोगकर्ताओं को बेहतर अनुभव मिलता है, बल्कि आपके सभी उपयोगकर्ताओं को भी बेहतर अनुभव मिलता है.

Android, स्टैंडर्ड यूज़र इंटरफ़ेस (यूआई) व्यू में सुलभता से जुड़ी कई सुविधाएं डिफ़ॉल्ट रूप से उपलब्ध कराता है. जैसे, TextView और Button. हालांकि, कस्टम व्यू बनाते समय आपको यह ध्यान रखना होगा कि कस्टम व्यू में, सुलभता से जुड़ी सुविधाएं कैसे उपलब्ध कराई जाएंगी. जैसे, स्क्रीन पर मौजूद कॉन्टेंट के बारे में बोलकर जानकारी देना.

इस टास्क में, आपको Android के स्क्रीन रीडर, TalkBack के बारे में जानकारी मिलेगी. साथ ही, आपको अपने ऐप्लिकेशन में बदलाव करने का तरीका बताया जाएगा, ताकि DialView कस्टम व्यू के लिए, बोलकर सुनाई जा सकने वाली जानकारी और ब्यौरे शामिल किए जा सकें.

चरण 1. TalkBack के बारे में जानें

TalkBack, Android में पहले से मौजूद स्क्रीन रीडर है. TalkBack की सुविधा चालू होने पर, उपयोगकर्ता बिना स्क्रीन देखे अपने Android डिवाइस का इस्तेमाल कर सकता है. ऐसा इसलिए, क्योंकि Android स्क्रीन पर मौजूद एलिमेंट के बारे में तेज़ आवाज़ में बताता है. दृष्टि बाधित उपयोगकर्ता, आपके ऐप्लिकेशन को इस्तेमाल करने के लिए TalkBack पर भरोसा कर सकते हैं.

इस टास्क में, आपको TalkBack को चालू करना है. इससे आपको यह समझने में मदद मिलेगी कि स्क्रीन रीडर कैसे काम करते हैं और ऐप्लिकेशन में नेविगेट कैसे किया जाता है.

  1. Android डिवाइस या एम्युलेटर पर, सेटिंग > सुलभता > TalkBack पर जाएं.
  2. TalkBack की सुविधा चालू करने के लिए, चालू/बंद करें टॉगल बटन पर टैप करें.
  3. अनुमतियों की पुष्टि करने के लिए, ठीक है पर टैप करें.
  4. अगर पूछा जाए, तो अपने डिवाइस के पासवर्ड की पुष्टि करें. अगर आपने पहली बार TalkBack चालू किया है, तो एक ट्यूटोरियल लॉन्च होगा. (ऐसा हो सकता है कि ट्यूटोरियल, पुराने डिवाइसों पर उपलब्ध न हो.)
  5. आंखें बंद करके ट्यूटोरियल को नेविगेट करने से आपको मदद मिल सकती है. अगर आपको आने वाले समय में ट्यूटोरियल को फिर से खोलना है, तो सेटिंग > सुलभता > TalkBack > सेटिंग > TalkBack ट्यूटोरियल लॉन्च करें पर जाएं.
  6. CustomFanController ऐप्लिकेशन को कंपाइल और चलाएं. इसके अलावा, इसे अपने डिवाइस पर खास जानकारी या हाल ही के बटन से भी खोला जा सकता है. TalkBack चालू होने पर, ध्यान दें कि ऐप्लिकेशन का नाम और लेबल TextView ("पंखे का कंट्रोल") का टेक्स्ट बोला जाता है. हालांकि, अगर DialView व्यू पर टैप किया जाता है, तो व्यू की स्थिति (डायल के लिए मौजूदा सेटिंग) या व्यू को चालू करने के लिए टैप करने पर होने वाली कार्रवाई के बारे में कोई जानकारी नहीं दी जाती है.

दूसरा चरण. डायल लेबल के लिए कॉन्टेंट की जानकारी जोड़ना

कॉन्टेंट के ब्यौरे से, आपके ऐप्लिकेशन में मौजूद व्यू के मतलब और मकसद के बारे में पता चलता है. इन लेबल की मदद से, Android की TalkBack सुविधा जैसे स्क्रीन रीडर, हर एलिमेंट के फ़ंक्शन के बारे में सटीक जानकारी दे पाते हैं. ImageView जैसे स्टैटिक व्यू के लिए, लेआउट फ़ाइल में व्यू के साथ कॉन्टेंट का ब्यौरा जोड़ा जा सकता है. इसके लिए, contentDescription एट्रिब्यूट का इस्तेमाल करें. टेक्स्ट व्यू (TextView और EditText) में, व्यू में मौजूद टेक्स्ट का इस्तेमाल कॉन्टेंट के ब्यौरे के तौर पर अपने-आप होता है.

पसंद के मुताबिक बनाए गए फ़ैन कंट्रोल व्यू के लिए, आपको व्यू पर क्लिक किए जाने पर कॉन्टेंट के ब्यौरे को डाइनैमिक तरीके से अपडेट करना होगा. इससे फ़ैन की मौजूदा सेटिंग के बारे में पता चलेगा.

  1. DialView क्लास में सबसे नीचे, updateContentDescription() फ़ंक्शन का एलान करें. इसमें कोई आर्ग्युमेंट या रिटर्न टाइप नहीं होता.
fun updateContentDescription() {
}
  1. updateContentDescription() के अंदर, कस्टम व्यू के लिए contentDescription प्रॉपर्टी को मौजूदा पंखे की स्पीड (बंद, 1, 2 या 3) से जुड़ी स्ट्रिंग रिसॉर्स में बदलें. ये वही लेबल हैं जिनका इस्तेमाल onDraw() में किया जाता है, जब स्क्रीन पर डायल बनाया जाता है.
fun updateContentDescription() {
   contentDescription = resources.getString(fanSpeed.label)
}
  1. ऊपर की ओर स्क्रोल करके init() ब्लॉक पर जाएं. इसके बाद, उस ब्लॉक के आखिर में updateContentDescription() को कॉल करें. इससे व्यू के शुरू होने पर, कॉन्टेंट की जानकारी शुरू हो जाती है.
init {
   isClickable = true
   // ...

   updateContentDescription()
}
  1. performClick() तरीके में, invalidate() से ठीक पहले updateContentDescription() को कॉल करने का एक और तरीका जोड़ें.
override fun performClick(): Boolean {
   if (super.performClick()) return true
   fanSpeed = fanSpeed.next()
   updateContentDescription()
   invalidate()
   return true
}
  1. ऐप्लिकेशन को कंपाइल और चलाएं. साथ ही, पक्का करें कि TalkBack चालू हो. डायल व्यू की सेटिंग बदलने के लिए टैप करें. ध्यान दें कि अब TalkBack, मौजूदा लेबल (बंद, 1, 2, 3) के साथ-साथ "चालू करने के लिए दो बार टैप करें" वाक्यांश भी बोलता है.

तीसरा चरण. क्लिक ऐक्शन के लिए ज़्यादा जानकारी जोड़ना

इसके बाद, आपको कुछ और करने की ज़रूरत नहीं है. अब TalkBack की मदद से, इस व्यू का इस्तेमाल किया जा सकता है. हालांकि, अगर आपके व्यू में यह जानकारी भी शामिल हो कि इसे चालू किया जा सकता है ("चालू करने के लिए दो बार टैप करें") और इसे चालू करने पर क्या होगा ("बदलने के लिए दो बार टैप करें" या "रीसेट करने के लिए दो बार टैप करें"), तो यह ज़्यादा मददगार होगा.

इसके लिए, सुलभता डेलिगेट का इस्तेमाल करके, सुलभता नोड की जानकारी वाले ऑब्जेक्ट में व्यू की कार्रवाई (यहां, क्लिक या टैप करने की कार्रवाई) के बारे में जानकारी जोड़ी जाती है. सुलभता डेलिगेट की मदद से, कंपोज़िशन (इनहेरिटेंस के बजाय) का इस्तेमाल करके, अपने ऐप्लिकेशन की सुलभता से जुड़ी सुविधाओं को पसंद के मुताबिक बनाया जा सकता है.

इस टास्क के लिए, Android Jetpack लाइब्रेरी (androidx.*) में मौजूद सुलभता क्लास का इस्तेमाल करें, ताकि यह पक्का किया जा सके कि ये क्लास पुराने सिस्टम के साथ काम करती हैं.

  1. DialView.kt में, init ब्लॉक में, व्यू पर ऐक्सेसिबिलिटी डेलिगेट को नए AccessibilityDelegateCompat ऑब्जेक्ट के तौर पर सेट करें. अनुरोध किए जाने पर, androidx.core.view.ViewCompat और androidx.core.view.AccessibilityDelegateCompat इंपोर्ट करें. इस रणनीति से, आपके ऐप्लिकेशन में पुराने सिस्टम के साथ काम करने की सुविधा सबसे ज़्यादा मिलती है.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   
})
  1. AccessibilityDelegateCompat ऑब्जेक्ट में, onInitializeAccessibilityNodeInfo() फ़ंक्शन को AccessibilityNodeInfoCompat ऑब्जेक्ट से बदलें और सुपर के तरीके को कॉल करें. निर्देश मिलने पर, androidx.core.view.accessibility.AccessibilityNodeInfoCompat इंपोर्ट करें.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   override fun onInitializeAccessibilityNodeInfo(host: View, 
                            info: AccessibilityNodeInfoCompat) {
      super.onInitializeAccessibilityNodeInfo(host, info)

   }  
})

हर व्यू में ऐक्सेसिबिलिटी नोड का ट्री होता है. यह ज़रूरी नहीं है कि यह व्यू के लेआउट कॉम्पोनेंट से मेल खाए. Android की सुलभता सेवाएं, उन नोड पर जाती हैं, ताकि व्यू के बारे में जानकारी मिल सके. जैसे, बोले जा सकने वाले कॉन्टेंट का ब्यौरा या उस व्यू पर की जा सकने वाली संभावित कार्रवाइयां. कस्टम व्यू बनाते समय, आपको नोड की जानकारी को भी बदलना पड़ सकता है, ताकि पहुंच से जुड़ी कस्टम जानकारी दी जा सके. इस मामले में, नोड की जानकारी को बदला जाएगा, ताकि यह पता चल सके कि व्यू की कार्रवाई के लिए कस्टम जानकारी मौजूद है.

  1. onInitializeAccessibilityNodeInfo() के अंदर, एक नया AccessibilityNodeInfoCompat.AccessibilityActionCompat ऑब्जेक्ट बनाएं और उसे customClick वैरिएबल को असाइन करें. कंस्ट्रक्टर में AccessibilityNodeInfo.ACTION_CLICK कॉन्स्टेंट और प्लेसहोल्डर स्ट्रिंग पास करें. अनुरोध किए जाने पर, इंपोर्ट AccessibilityNodeInfo करें.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   override fun onInitializeAccessibilityNodeInfo(host: View, 
                            info: AccessibilityNodeInfoCompat) {
      super.onInitializeAccessibilityNodeInfo(host, info)
      val customClick = AccessibilityNodeInfoCompat.AccessibilityActionCompat(
         AccessibilityNodeInfo.ACTION_CLICK,
        "placeholder"
      )
   }  
})

AccessibilityActionCompat क्लास, ऐक्सेसिबिलिटी के लिए व्यू पर की गई कार्रवाई को दिखाती है. आम तौर पर, क्लिक या टैप को कार्रवाई माना जाता है. हालांकि, फ़ोकस पाना या खोना, क्लिपबोर्ड की कार्रवाई (कट/कॉपी/चिपकाएं) या व्यू में स्क्रोल करना भी कार्रवाई में शामिल हो सकता है. इस क्लास के कंस्ट्रक्टर के लिए, कार्रवाई का कॉन्स्टेंट (यहां, AccessibilityNodeInfo.ACTION_CLICK) और एक स्ट्रिंग की ज़रूरत होती है. TalkBack इस स्ट्रिंग का इस्तेमाल करके यह बताता है कि कार्रवाई क्या है.

  1. स्ट्रिंग रिसॉर्स को वापस पाने के लिए, "placeholder" स्ट्रिंग को context.getString() पर कॉल करने से बदलें. किसी खास संसाधन के लिए, पंखे की मौजूदा स्पीड की जांच करें. अगर स्पीड फ़िलहाल FanSpeed.HIGH है, तो स्ट्रिंग "Reset" होगी. अगर पंखे की स्पीड कुछ और है, तो स्ट्रिंग "Change." इन स्ट्रिंग रिसॉर्स को बाद में बनाया जाएगा.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   override fun onInitializeAccessibilityNodeInfo(host: View, 
                            info: AccessibilityNodeInfoCompat) {
      super.onInitializeAccessibilityNodeInfo(host, info)
      val customClick = AccessibilityNodeInfoCompat.AccessibilityActionCompat(
         AccessibilityNodeInfo.ACTION_CLICK,
        context.getString(if (fanSpeed !=  FanSpeed.HIGH) R.string.change else R.string.reset)
      )
   }  
})
  1. customClick की परिभाषा के लिए क्लोज़िंग पैरंटheses के बाद, addAction() तरीके का इस्तेमाल करके, नोड की जानकारी वाले ऑब्जेक्ट में नई ऐक्सेसिबिलिटी कार्रवाई जोड़ें.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   override fun onInitializeAccessibilityNodeInfo(host: View, 
                            info: AccessibilityNodeInfoCompat) {
       super.onInitializeAccessibilityNodeInfo(host, info)
       val customClick = AccessibilityNodeInfoCompat.AccessibilityActionCompat(
           AccessibilityNodeInfo.ACTION_CLICK,
           context.getString(if (fanSpeed !=  FanSpeed.HIGH) 
                                 R.string.change else R.string.reset)
       )
       info.addAction(customClick)
   }
})
  1. res/values/strings.xml में, "बदलें" और "रीसेट करें" के लिए स्ट्रिंग रिसॉर्स जोड़ें.
<string name="change">Change</string>
<string name="reset">Reset</string>
  1. ऐप्लिकेशन को कंपाइल और चलाएं. साथ ही, पक्का करें कि TalkBack चालू हो. अब ध्यान दें कि "चालू करने के लिए दो बार टैप करें" वाक्यांश, अब "बदलने के लिए दो बार टैप करें" (अगर पंखे की स्पीड ज़्यादा या 3 से कम है) या "रीसेट करने के लिए दो बार टैप करें" (अगर पंखे की स्पीड पहले से ही ज़्यादा या 3 पर है) में बदल गया है. ध्यान दें कि "डबल-टैप करके..." प्रॉम्प्ट, TalkBack सेवा ही उपलब्ध कराती है.

पूरे किए गए कोडलैब का कोड डाउनलोड करें..

$  git clone https://github.com/googlecodelabs/android-kotlin-drawing-custom-views


इसके अलावा, रिपॉज़िटरी को Zip फ़ाइल के तौर पर डाउनलोड किया जा सकता है. इसके बाद, इसे अनज़िप करके Android Studio में खोला जा सकता है.

ज़िप फ़ाइल डाउनलोड करें

  • View सबक्लास, जैसे कि EditText के लुक और व्यवहार के हिसाब से कस्टम व्यू बनाने के लिए, एक नई क्लास जोड़ें जो उस सबक्लास को बढ़ाती है. इसके बाद, सबक्लास के कुछ तरीकों को बदलकर बदलाव करें.
  • किसी भी साइज़ और शेप का कस्टम व्यू बनाने के लिए, एक नई क्लास जोड़ें. यह क्लास View को एक्सटेंड करती है.
  • व्यू के आकार और बुनियादी लुक को तय करने के लिए, onDraw() जैसे View तरीकों को बदलें.
  • व्यू को फिर से ड्रा करने के लिए, invalidate() का इस्तेमाल करें.
  • परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, वैरिएबल असाइन करें. साथ ही, onDraw() में उनका इस्तेमाल करने से पहले, ड्रॉइंग और पेंटिंग के लिए ज़रूरी वैल्यू असाइन करें. जैसे, सदस्य वैरिएबल के शुरू होने पर.
  • व्यू के इंटरैक्टिव व्यवहार को दिखाने के लिए, कस्टम व्यू में OnClickListener() के बजाय performClick() को बदलें. इससे आपको या अन्य Android डेवलपर को, कस्टम व्यू क्लास का इस्तेमाल करने की अनुमति मिलती है. इससे वे onClickListener() का इस्तेमाल करके, ज़्यादा सुविधाएं दे सकते हैं.
  • कस्टम व्यू को एक्सएमएल लेआउट फ़ाइल में जोड़ें. साथ ही, उसके एट्रिब्यूट जोड़कर यह तय करें कि वह कैसा दिखेगा. ऐसा ही तरीका अन्य यूज़र इंटरफ़ेस (यूआई) एलिमेंट के लिए भी इस्तेमाल किया जाता है.
  • कस्टम एट्रिब्यूट तय करने के लिए, values फ़ोल्डर में attrs.xml फ़ाइल बनाएं. इसके बाद, एक्सएमएल लेआउट फ़ाइल में कस्टम व्यू के लिए कस्टम एट्रिब्यूट का इस्तेमाल किया जा सकता है.

Udacity का कोर्स:

Android डेवलपर का दस्तावेज़:

वीडियो:

इस सेक्शन में, उन छात्र-छात्राओं के लिए होमवर्क असाइनमेंट की सूची दी गई है जो किसी शिक्षक के कोर्स के हिस्से के तौर पर इस कोडलैब पर काम कर रहे हैं. शिक्षक के पास ये विकल्प होते हैं:

  • अगर ज़रूरी हो, तो होमवर्क असाइन करें.
  • छात्र-छात्राओं को बताएं कि होमवर्क असाइनमेंट कैसे सबमिट किए जाते हैं.
  • होमवर्क असाइनमेंट को ग्रेड दें.

शिक्षक इन सुझावों का इस्तेमाल अपनी ज़रूरत के हिसाब से कर सकते हैं. साथ ही, वे चाहें, तो कोई दूसरा होमवर्क भी दे सकते हैं.

अगर आपको यह कोडलैब खुद से पूरा करना है, तो अपनी जानकारी की जांच करने के लिए, इन होमवर्क असाइनमेंट का इस्तेमाल करें.

Question 1

कस्टम व्यू को पहली बार साइज़ असाइन किए जाने पर, पोज़िशन, डाइमेंशन, और अन्य वैल्यू का हिसाब लगाने के लिए, किस तरीके को बदला जाता है?

onMeasure()

onSizeChanged()

invalidate()

onDraw()

दूसरा सवाल

अगर आपको यह दिखाना है कि एट्रिब्यूट की वैल्यू बदलने के बाद, आपको onDraw() की मदद से व्यू को फिर से ड्रा करना है, तो यूज़र इंटरफ़ेस (यूआई) थ्रेड से कौनसे तरीके को कॉल किया जाता है?

▢ onMeasure()

▢ onSizeChanged()

▢ invalidate()

▢ getVisibility()

तीसरा सवाल

अपने कस्टम व्यू में इंटरैक्टिविटी जोड़ने के लिए, आपको View के किस तरीके को बदलना चाहिए?

▢ setOnClickListener()

▢ onSizeChanged()

▢ isClickable()

▢ performClick()

इस कोर्स में मौजूद अन्य कोडलैब के लिंक के लिए, Advanced Android in Kotlin कोडलैब का लैंडिंग पेज देखें.