अगर आपके ऐप्लिकेशन को कस्टम व्यू कॉम्पोनेंट की ज़रूरत है, तो आपको व्यू को ज़्यादा सुलभ बनाना होगा. इस पेज पर बताए गए तरीके से, कस्टम व्यू की सुलभता को बेहतर बनाया जा सकता है:
- डायरेक्शनल कंट्रोलर के क्लिक को मैनेज करना.
- सुलभता एपीआई के तरीकों को लागू करना.
- अपने कस्टम व्यू के लिए,
AccessibilityEventऑब्जेक्ट भेजना. - अपने व्यू के लिए,
AccessibilityEventऔरAccessibilityNodeInfoको पॉप्युलेट करना.
डायरेक्शनल कंट्रोलर के क्लिक को मैनेज करना
ज़्यादातर डिवाइसों पर, डायरेक्शनल कंट्रोलर का इस्तेमाल करके किसी व्यू पर क्लिक करने से, फ़िलहाल फ़ोकस में मौजूद व्यू को KeyEvent मिलता है. इसमें KEYCODE_DPAD_CENTER शामिल होता है. Android के सभी स्टैंडर्ड व्यू, KEYCODE_DPAD_CENTER को सही तरीके से मैनेज करते हैं. कस्टम View कंट्रोल बनाते समय, पक्का करें कि इस इवेंट का वही असर हो जो टचस्क्रीन पर व्यू को टैप करने पर होता है.
आपके कस्टम कंट्रोल को KEYCODE_ENTER इवेंट को KEYCODE_DPAD_CENTER की तरह ही मैनेज करना चाहिए. इससे उपयोगकर्ताओं के लिए, पूरे कीबोर्ड के साथ इंटरैक्शन करना आसान हो जाता है.
सुलभता एपीआई के तरीकों को लागू करना
सुलभता इवेंट, आपके ऐप्लिकेशन के विज़ुअल इंटरफ़ेस कॉम्पोनेंट के साथ उपयोगकर्ताओं के इंटरैक्शन के बारे में मैसेज होते हैं. इन मैसेज को सुलभता सेवाओं से मैनेज किया जाता है. ये सेवाएं, इन इवेंट में मौजूद जानकारी का इस्तेमाल करके, पूरक फ़ीडबैक और प्रॉम्प्ट जनरेट करती हैं. सुलभता
तरीके, View और
View.AccessibilityDelegate
क्लास का हिस्सा होते हैं. ये तरीके इस तरह हैं:
dispatchPopulateAccessibilityEvent()onPopulateAccessibilityEvent() को कॉल करता है. इसके बाद, इस
व्यू के हर चाइल्ड के लिए dispatchPopulateAccessibilityEvent() तरीके को कॉल करता है. onInitializeAccessibilityEvent()TextView या
Button के अलावा इंटरैक्टिव कंट्रोल उपलब्ध कराता है, तो इस तरीके को बदलें
और अपने व्यू के बारे में ज़्यादा जानकारी सेट करें. जैसे, पासवर्ड फ़ील्ड का टाइप, चेकबॉक्स
का टाइप या ऐसी स्थितियां जिनसे उपयोगकर्ता इंटरैक्शन या फ़ीडबैक को इवेंट में शामिल किया जा सके. इसके लिए, इस
तरीके का इस्तेमाल करें. अगर आपने इस तरीके को बदला है, तो इसके सुपर इंप्लीमेंटेशन को कॉल करें और सिर्फ़ उन प्रॉपर्टी में बदलाव करें जिन्हें सुपर क्लास ने सेट नहीं किया है.onInitializeAccessibilityNodeInfo()View लागू किए गए वर्शन में, व्यू की प्रॉपर्टी का स्टैंडर्ड सेट होता है. हालांकि, अगर आपका
कस्टम व्यू, सामान्य TextView या
Button के अलावा इंटरैक्टिव कंट्रोल उपलब्ध कराता है, तो इस तरीके को बदलें और अपने व्यू के बारे में ज़्यादा जानकारी,
इस तरीके से मैनेज किए जाने वाले AccessibilityNodeInfo ऑब्जेक्ट में सेट करें.onPopulateAccessibilityEvent()AccessibilityEvent का बोलकर सुनाया जाने वाला टेक्स्ट प्रॉम्प्ट सेट करता है. अगर व्यू, ऐसे व्यू का चाइल्ड है जो सुलभता
इवेंट जनरेट करता है, तो भी इसे कॉल किया जाता है.
onRequestSendAccessibilityEvent()AccessibilityEvent इस चरण से, पैरंट व्यू, सुलभता
इवेंट में ज़्यादा जानकारी जोड़ सकता है. इस तरीके को सिर्फ़ तब लागू करें, जब आपके कस्टम व्यू में
चाइल्ड व्यू हो सकते हैं और पैरंट व्यू, सुलभता इवेंट को कॉन्टेक्स्ट की जानकारी दे सकता है.
यह जानकारी, सुलभता सेवाओं के लिए काम की होती है.sendAccessibilityEvent()- जब कोई उपयोगकर्ता किसी व्यू पर कोई कार्रवाई करता है, तो सिस्टम इस तरीके को कॉल करता है. इवेंट को उपयोगकर्ता की कार्रवाई के टाइप के हिसाब से बांटा जाता है. जैसे,
TYPE_VIEW_CLICKED. आम तौर पर, जब भी आपके कस्टम व्यू का कॉन्टेंट बदलता है, तब आपकोAccessibilityEventभेजना होगा. sendAccessibilityEventUnchecked()- इस तरीके का इस्तेमाल तब किया जाता है, जब कॉलिंग कोड को डिवाइस पर सुलभता चालू होने की जांच को सीधे तौर पर कंट्रोल करना होता है (
AccessibilityManager.isEnabled()). अगर आपने इस तरीके को लागू किया है, तो कॉल इस तरह करें जैसे कि सुलभता चालू है. भले ही, सिस्टम सेटिंग कुछ भी हो. आम तौर पर, आपको कस्टम व्यू के लिए इस तरीके को लागू करने की ज़रूरत नहीं होती. dispatchPopulateAccessibilityEvent()onInitializeAccessibilityEvent()onInitializeAccessibilityNodeInfo()onPopulateAccessibilityEvent()TYPE_VIEW_CLICKEDTYPE_VIEW_FOCUSEDTYPE_VIEW_HOVER_ENTERTYPE_VIEW_HOVER_EXITTYPE_VIEW_LONG_CLICKEDTYPE_VIEW_SCROLLED- इंटरप्रेट की गई क्लिक की कार्रवाई के लिए, सही
AccessibilityEventजनरेट करना. - सुलभता सेवाओं को, टच स्क्रीन का इस्तेमाल न कर पाने वाले उपयोगकर्ताओं के लिए, क्लिक की कस्टम कार्रवाई करने की अनुमति देना.
सुलभता की सुविधा देने के लिए, अपने कस्टम व्यू क्लास में, सुलभता के ऊपर बताए गए तरीकों को सीधे तौर पर बदलें और लागू करें.
कम से कम, अपने कस्टम व्यू क्लास के लिए, सुलभता के ये तरीके लागू करें:
सुलभता इवेंट भेजना
अपने कस्टम व्यू की खास जानकारी के आधार पर, हो सकता है कि उसे अलग-अलग समय पर या ऐसे इवेंट के लिए AccessibilityEvent ऑब्जेक्ट भेजने की ज़रूरत हो जिन्हें डिफ़ॉल्ट तौर पर लागू किए गए वर्शन से मैनेज नहीं किया जाता. View क्लास, इन इवेंट टाइप के लिए डिफ़ॉल्ट तौर पर लागू किया गया वर्शन उपलब्ध कराती है:
आम तौर पर, जब भी आपके कस्टम व्यू का कॉन्टेंट बदलता है, तब आपको AccessibilityEvent भेजना होगा. उदाहरण के लिए, अगर आपने कस्टम स्लाइडर बार लागू किया है, तो उपयोगकर्ता बाएं या दाएं ऐरो कुंजी दबाकर कोई संख्या वाली वैल्यू चुन सकता है. ऐसे में, जब भी स्लाइडर की वैल्यू बदलती है, तो आपके कस्टम व्यू को TYPE_VIEW_TEXT_CHANGED का इवेंट एमिट करना होगा. कोड के इस उदाहरण में, इस इवेंट की रिपोर्ट करने के लिए, sendAccessibilityEvent() तरीके के इस्तेमाल के बारे में बताया गया है.
Kotlin
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when(keyCode) { KeyEvent.KEYCODE_DPAD_LEFT -> { currentValue-- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED) true } ... } }
Java
@Override public boolean onKeyUp (int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { currentValue--; sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); return true; } ... }
सुलभता इवेंट को पॉप्युलेट करना
हर AccessibilityEvent में, ज़रूरी प्रॉपर्टी का सेट होता है. इससे व्यू की मौजूदा स्थिति के बारे में पता चलता है. इन प्रॉपर्टी में, व्यू का क्लास नेम, कॉन्टेंट की जानकारी, और चुनी गई स्थिति जैसी चीज़ें शामिल होती हैं. हर इवेंट टाइप के लिए ज़रूरी प्रॉपर्टी के बारे में, AccessibilityEvent के रेफ़रंस दस्तावेज़ में बताया गया है.
View को लागू करने पर, इन ज़रूरी प्रॉपर्टी के लिए डिफ़ॉल्ट वैल्यू मिलती हैं. इनमें से कई वैल्यू, जैसे कि क्लास नेम और इवेंट का टाइमस्टैंप, अपने-आप उपलब्ध हो जाते हैं. अगर कस्टम व्यू कॉम्पोनेंट बनाया जा रहा है, तो आपको व्यू के कॉन्टेंट और उसकी विशेषताओं के बारे में जानकारी देनी होगी. यह जानकारी, बटन के लेबल जितनी आसान हो सकती है. इसमें, इवेंट में जोड़ी जाने वाली स्थिति की ज़्यादा जानकारी भी शामिल हो सकती है.
AccessibilityEvent में मौजूद जानकारी को पॉप्युलेट करने या उसमें बदलाव करने के लिए,
onPopulateAccessibilityEvent()
और
onInitializeAccessibilityEvent()
तरीकों का इस्तेमाल करें. खास तौर पर, इवेंट के टेक्स्ट कॉन्टेंट को जोड़ने या उसमें बदलाव करने के लिए, onPopulateAccessibilityEvent() तरीके का इस्तेमाल करें. इस कॉन्टेंट को, TalkBack जैसी सुलभता सेवाओं की मदद से, सुनाई देने वाले प्रॉम्प्ट में बदला जाता है. इवेंट के बारे में ज़्यादा जानकारी पॉप्युलेट करने के लिए, onInitializeAccessibilityEvent() तरीके का इस्तेमाल करें. जैसे, व्यू की चुनी गई स्थिति.
इसके अलावा, onInitializeAccessibilityNodeInfo() तरीका लागू करें. सुलभता सेवाएं, इस तरीके से पॉप्युलेट किए गए AccessibilityNodeInfo ऑब्जेक्ट का इस्तेमाल करके, व्यू के उस क्रम की जांच करती हैं जिससे सुलभता इवेंट जनरेट होता है. साथ ही, उपयोगकर्ताओं को सही फ़ीडबैक देती हैं.
कोड के इस उदाहरण में, अपने व्यू में इन तीनों तरीकों को बदलने का तरीका बताया गया है:
Kotlin
override fun onPopulateAccessibilityEvent(event: AccessibilityEvent?) { super.onPopulateAccessibilityEvent(event) // Call the super implementation to populate its text for the // event. Then, add text not present in a super class. // You typically only need to add the text for the custom view. if (text?.isNotEmpty() == true) { event?.text?.add(text) } } override fun onInitializeAccessibilityEvent(event: AccessibilityEvent?) { super.onInitializeAccessibilityEvent(event) // Call the super implementation to let super classes // set appropriate event properties. Then, add the new checked // property that is not supported by a super class. event?.isChecked = isChecked() } override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo?) { super.onInitializeAccessibilityNodeInfo(info) // Call the super implementation to let super classes set // appropriate info properties. Then, add the checkable and checked // properties that are not supported by a super class. info?.isCheckable = true info?.isChecked = isChecked() // You typically only need to add the text for the custom view. if (text?.isNotEmpty() == true) { info?.text = text } }
Java
@Override public void onPopulateAccessibilityEvent(AccessibilityEvent event) { super.onPopulateAccessibilityEvent(event); // Call the super implementation to populate its text for the // event. Then, add the text not present in a super class. // You typically only need to add the text for the custom view. CharSequence text = getText(); if (!TextUtils.isEmpty(text)) { event.getText().add(text); } } @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); // Call the super implementation to let super classes // set appropriate event properties. Then, add the new checked // property that is not supported by a super class. event.setChecked(isChecked()); } @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); // Call the super implementation to let super classes set // appropriate info properties. Then, add the checkable and checked // properties that are not supported by a super class. info.setCheckable(true); info.setChecked(isChecked()); // You typically only need to add the text for the custom view. CharSequence text = getText(); if (!TextUtils.isEmpty(text)) { info.setText(text); } }
इन तरीकों को, अपने कस्टम व्यू क्लास में सीधे तौर पर लागू किया जा सकता है.
सुलभता के लिए, पसंद के मुताबिक बनाया गया कॉन्टेक्स्ट उपलब्ध कराना
सुलभता सेवाएं, यूज़र इंटरफ़ेस के उस कॉम्पोनेंट के व्यू के क्रम की जांच कर सकती हैं जिससे सुलभता इवेंट जनरेट होता है. इससे सुलभता सेवाएं, उपयोगकर्ताओं की मदद करने के लिए, कॉन्टेक्स्ट की ज़्यादा जानकारी उपलब्ध करा सकती हैं.
कुछ मामलों में, सुलभता सेवाओं को व्यू के क्रम से पूरी जानकारी नहीं मिल पाती. इसका एक उदाहरण, कस्टम इंटरफ़ेस कंट्रोल है. इसमें दो या उससे ज़्यादा ऐसे इलाके होते हैं जिन पर अलग-अलग क्लिक किया जा सकता है. जैसे, कैलेंडर कंट्रोल. इस मामले में, सेवाओं को पूरी जानकारी नहीं मिल पाती, क्योंकि क्लिक किए जा सकने वाले सब-सेक्शन, व्यू के क्रम का हिस्सा नहीं होते.
पहली इमेज. चुने जा सकने वाले दिन के एलिमेंट वाला कस्टम कैलेंडर व्यू.
पहली इमेज में दिए गए उदाहरण में, पूरे कैलेंडर को एक व्यू के तौर पर लागू किया गया है. इसलिए, डेवलपर की ओर से ज़्यादा जानकारी उपलब्ध कराए जाने तक, सुलभता सेवाओं को व्यू के कॉन्टेंट और व्यू में उपयोगकर्ता के चुने गए विकल्प के बारे में पूरी जानकारी नहीं मिलती. उदाहरण के लिए, अगर कोई उपयोगकर्ता क्लिक करता है लेबल वाले दिन पर 17, तो सुलभता फ़्रेमवर्क को सिर्फ़ जानकारी मिलती है पूरे कैलेंडर कंट्रोल के लिए. इस मामले में, TalkBack सुलभता सेवा "कैलेंडर" या "अप्रैल का कैलेंडर" की सूचना देती है. साथ ही, उपयोगकर्ता को यह पता नहीं चलता कि कौनसी तारीख चुनी गई है.
ऐसी स्थितियों में, सुलभता सेवाओं के लिए कॉन्टेक्स्ट की पूरी जानकारी उपलब्ध कराने के लिए, फ़्रेमवर्क में वर्चुअल व्यू का क्रम तय करने का तरीका दिया गया है. वर्चुअल व्यू का क्रम , ऐप्लिकेशन डेवलपर के लिए, सुलभता सेवाओं को पूरक व्यू का क्रम उपलब्ध कराने का एक तरीका है. यह क्रम, स्क्रीन पर मौजूद जानकारी से ज़्यादा मेल खाता है. इस तरीके से, सुलभता सेवाएं, उपयोगकर्ताओं को कॉन्टेक्स्ट की ज़्यादा काम की जानकारी उपलब्ध करा सकती हैं.
एक और स्थिति में, वर्चुअल व्यू के क्रम की ज़रूरत पड़ सकती है. यह स्थिति, ऐसे यूज़र इंटरफ़ेस से जुड़ी है जिसमें View कंट्रोल का सेट शामिल होता है. इन कंट्रोल के फ़ंक्शन एक-दूसरे से काफ़ी मिलते-जुलते होते हैं. इनमें से किसी एक कंट्रोल पर की गई कार्रवाई से, एक या उससे ज़्यादा एलिमेंट के कॉन्टेंट पर असर पड़ता है. जैसे, अलग-अलग अप और डाउन बटन वाला नंबर पिकर. इस मामले में, सुलभता सेवाओं को पूरी जानकारी नहीं मिल पाती, क्योंकि एक कंट्रोल पर की गई कार्रवाई से दूसरे में कॉन्टेंट बदल जाता है. साथ ही, हो सकता है कि सेवा को उन कंट्रोल के बीच के संबंध के बारे में पता न हो.
इस स्थिति को मैनेज करने के लिए, मिलते-जुलते कंट्रोल को एक कंटेनिंग व्यू के साथ ग्रुप करें. साथ ही, इस कंटेनर से वर्चुअल व्यू का क्रम उपलब्ध कराएं, ताकि कंट्रोल से मिली जानकारी और उसके व्यवहार को साफ़ तौर पर दिखाया जा सके.
किसी व्यू के लिए वर्चुअल व्यू का क्रम उपलब्ध कराने के लिए, अपने कस्टम व्यू या व्यू ग्रुप में
getAccessibilityNodeProvider()
तरीके को बदलें और
AccessibilityNodeProviderको लागू करने का तरीका दिखाएं.
ViewCompat.getAccessibilityNodeProvider() तरीके के साथ, Support Library का इस्तेमाल करके, वर्चुअल व्यू का क्रम लागू किया जा सकता है. साथ ही, AccessibilityNodeProviderCompat के साथ लागू करने का तरीका उपलब्ध कराया जा सकता है.
सुलभता सेवाओं को जानकारी उपलब्ध कराने और सुलभता फ़ोकस को मैनेज करने के काम को आसान बनाने के लिए, इसके बजाय ExploreByTouchHelper को लागू किया जा सकता है.
यह AccessibilityNodeProviderCompat उपलब्ध कराता है. इसे
setAccessibilityDelegate को कॉल करके, व्यू के
AccessibilityDelegateCompat के तौर पर अटैच किया जा सकता है.
उदाहरण के लिए, ExploreByTouchHelperActivity देखें.
ExploreByTouchHelper का इस्तेमाल, फ़्रेमवर्क के विजेट भी करते हैं. जैसे, CalendarView. इसके लिए, इसके चाइल्ड व्यू SimpleMonthView का इस्तेमाल किया जाता है.
टच के कस्टम इवेंट मैनेज करना
कस्टम व्यू कंट्रोल के लिए, टच के नॉन-स्टैंडर्ड इवेंट के व्यवहार की ज़रूरत पड़ सकती है. इसे इन उदाहरणों में दिखाया गया है.
क्लिक पर आधारित कार्रवाइयां तय करना
अगर आपका विजेट,
OnClickListener या
OnLongClickListener
इंटरफ़ेस का इस्तेमाल करता है, तो सिस्टम आपके लिए
ACTION_CLICK
और
ACTION_LONG_CLICK
कार्रवाइयों को मैनेज करता है. अगर आपका ऐप्लिकेशन, ज़्यादा कस्टमाइज़ किए गए विजेट का इस्तेमाल करता है, तो यह
OnTouchListener इंटरफ़ेस पर निर्भर करता है. ऐसे में,
क्लिक पर आधारित सुलभता कार्रवाइयों के लिए, कस्टम हैंडलर तय करें. इसके लिए, हर कार्रवाई के लिए
replaceAccessibilityAction()
तरीके को कॉल करें. जैसा कि कोड के इस स्निपेट में दिखाया गया है:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { ... // Assumes that the widget is designed to select text when tapped, and selects // all text when tapped and held. In its strings.xml file, this app sets // "select" to "Select" and "select_all" to "Select all". ViewCompat.replaceAccessibilityAction( binding.textSelectWidget, ACTION_CLICK, getString(R.string.select) ) { view, commandArguments -> selectText() } ViewCompat.replaceAccessibilityAction( binding.textSelectWidget, ACTION_LONG_CLICK, getString(R.string.select_all) ) { view, commandArguments -> selectAllText() } }
Java
@Override protected void onCreate(Bundle savedInstanceState) { ... // Assumes that the widget is designed to select text when tapped, and select // all text when tapped and held. In its strings.xml file, this app sets // "select" to "Select" and "select_all" to "Select all". ViewCompat.replaceAccessibilityAction( binding.textSelectWidget, ACTION_CLICK, getString(R.string.select), (view, commandArguments) -> selectText()); ViewCompat.replaceAccessibilityAction( binding.textSelectWidget, ACTION_LONG_CLICK, getString(R.string.select_all), (view, commandArguments) -> selectAllText()); }
क्लिक के कस्टम इवेंट बनाना
कस्टम कंट्रोल, ACTION_DOWN और ACTION_UP इवेंट का पता लगाने और क्लिक का खास इवेंट ट्रिगर करने के लिए, onTouchEvent(MotionEvent) लिसनर तरीके का इस्तेमाल कर सकता है. सुलभता सेवाओं के साथ काम करने की सुविधा बनाए रखने के लिए, क्लिक के इस कस्टम इवेंट को मैनेज करने वाले कोड को यह काम करना होगा:
इन ज़रूरी शर्तों को असरदार तरीके से मैनेज करने के लिए, आपके कोड को performClick() तरीके को बदलना होगा. इसे इस तरीके के सुपर इंप्लीमेंटेशन को कॉल करना होगा. इसके बाद, क्लिक इवेंट के लिए ज़रूरी कार्रवाइयां करनी होंगी. जब क्लिक की कस्टम कार्रवाई का पता चलता है, तो उस कोड को आपके performClick() तरीके को कॉल करना होगा. कोड के इस उदाहरण में, इस पैटर्न के बारे में बताया गया है.
Kotlin
class CustomTouchView(context: Context) : View(context) { var downTouch = false override fun onTouchEvent(event: MotionEvent): Boolean { super.onTouchEvent(event) // Listening for the down and up touch events. return when (event.action) { MotionEvent.ACTION_DOWN -> { downTouch = true true } MotionEvent.ACTION_UP -> if (downTouch) { downTouch = false performClick() // Call this method to handle the response and // enable accessibility services to // perform this action for a user who can't // tap the touchscreen. true } else { false } else -> false // Return false for other touch events. } } override fun performClick(): Boolean { // Calls the super implementation, which generates an AccessibilityEvent // and calls the onClick() listener on the view, if any. super.performClick() // Handle the action for the custom click here. return true } }
Java
class CustomTouchView extends View { public CustomTouchView(Context context) { super(context); } boolean downTouch = false; @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); // Listening for the down and up touch events switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downTouch = true; return true; case MotionEvent.ACTION_UP: if (downTouch) { downTouch = false; performClick(); // Call this method to handle the response and // enable accessibility services to // perform this action for a user who can't // tap the touchscreen. return true; } } return false; // Return false for other touch events. } @Override public boolean performClick() { // Calls the super implementation, which generates an AccessibilityEvent // and calls the onClick() listener on the view, if any. super.performClick(); // Handle the action for the custom click here. return true; } }
ऊपर दिया गया पैटर्न, यह पक्का करने में मदद करता है कि क्लिक का कस्टम इवेंट, सुलभता सेवाओं के साथ काम करे. इसके लिए, performClick() तरीके का इस्तेमाल करके, सुलभता इवेंट जनरेट किया जाता है. साथ ही, सुलभता सेवाओं को, क्लिक के कस्टम इवेंट को करने वाले उपयोगकर्ता की ओर से कार्रवाई करने के लिए, एंट्री पॉइंट उपलब्ध कराया जाता है.