पहली बार Android योगदान के लिए उदाहरणों पर शोध करते समय, कोटलिन में लिखे गए एनिमेशन के लिए कुछ उदाहरण मौजूद थे। देशी एनिमेशन में अभिगम्यता संबंधी विचारों के कुछ कोड उदाहरण भी थे।
तो अब हम शुरू करें! आइए कोटलिन में एक देशी 'विस्तार' एनीमेशन लिखने पर ध्यान दें, और बात करें कि टॉकबैक या बढ़े हुए टेक्स्ट वाले लोगों की सहायता कैसे करें। इस उदाहरण रेपो में सभी कोड उपलब्ध हैं, इसके भीतर एक एनिमेटेड दृश्य के साथ एकल गतिविधि बनाना। यह जिस कोड पर आधारित है, वह कैलम टर्नर के साथ मिलकर लिखा गया था।
Android एक्सेसिबिलिटी (a11y)
सभी Android डिवाइस में टॉकबैक नाम का एक अंतर्निहित स्क्रीन रीडर होता है। इसे डिवाइस की सेटिंग से चालू किया जा सकता है, और इसमें पहली बार उपयोग गाइड भी शामिल है। जेस्चर का उपयोग पृष्ठ के चारों ओर नेविगेट करने के लिए किया जाता है, जिसमें फ़ोकस किए गए तत्वों के विवरण को ज़ोर से पढ़ा जाता है। इसके बिना, कई दृष्टिबाधित उपयोगकर्ताओं के लिए एक ऐप अनुपयोगी हो जाता है।
महत्वपूर्ण महत्व यह है कि सही तत्व फोकस करने योग्य हैं, विवरण हैं, और दृश्य में परिवर्तन की घोषणा की गई है।
उसी सेटिंग मेनू के भीतर डिफ़ॉल्ट आधार फ़ॉन्ट आकार को 1.0 से स्केलिंग, समायोजित किया जा सकता है। दृश्य को फ़ॉन्ट आकार में इस परिवर्तन पर प्रतिक्रिया देनी चाहिए, सभी तत्व अभी भी मौजूद हैं और कार्य कर रहे हैं।
लेआउट
हम यहां लेआउट की स्टाइलिंग बारीकियों को नहीं देखेंगे क्योंकि वे इस उदाहरण के लिए काफी विशिष्ट हैं, लेकिन एक्सेसिबिलिटी टच हाइलाइट करने लायक हैं।
दो गुणों का उपयोग किया जाता है:android:contentDescription
और android:importantForAccessibility
।
contentDescription
जब कोई तत्व फोकस करता है तो उसे पढ़ा जाता है। किसी भी छवि दृश्य के लिए जो फ़ोकस प्राप्त करता है, यह आवश्यक है, अन्यथा एक स्क्रीन रीडर इसके बजाय उपयोगकर्ता को बेकार 'बिना लेबल वाला' पढ़ेगा।
यदि यह एक बटन होता तो यह डिफ़ॉल्ट रूप से '<विवरण> बटन, सक्रिय करने के लिए डबल टैप' पढ़ता, लेकिन हमारे इमेज व्यू आइकन के लिए हम मैन्युअल रूप से कार्रवाई निर्दिष्ट करते हैं क्योंकि हमारे पास यह डिफ़ॉल्ट नहीं है।
android:contentDescription="tap to toggle extra person information"
हम importantForAccessibility:no
. का भी उपयोग करते हैं '+' टेक्स्ट व्यू के लिए फोकस बंद करने के लिए, क्योंकि दो बैज के नीचे का टेक्स्ट एक विवरण प्रदान करता है और इसलिए '+' जोर से पढ़ने पर मददगार से ज्यादा भ्रमित करने वाला होता है।
इन दोनों के लिए, टॉकबैक चालू होने पर किसी वास्तविक डिवाइस पर मैन्युअल परीक्षण इस बात का सबसे अच्छा संकेत है कि क्या दृश्य के बिना संदर्भ समझ में आता है।
एनीमेशन का विस्तार करें
हमारा ऐनिमेशन एक 'जानकारी' आइकन टैप पर सक्रिय होगा, जो विवरण अनुभाग के विस्तार को चालू करेगा।
एनीमेशन कोड पर ध्यान केंद्रित करने की अनुमति देने के लिए हम यह सब एक ही गतिविधि के अंदर करेंगे। एक वास्तविक दुनिया ऐप में, जिस दृश्य पर इसे लागू किया जाता है, वह अपने स्वयं के टुकड़े या पुनर्चक्रण दृश्य के भीतर होने की अधिक संभावना है, इसलिए अधिक सारगर्भित कोड संरचना का उपयोग किया जाएगा।
श्रोता सेट करना
हमारे उदाहरण गतिविधि के भीतर onCreate
हमें पहले अपने आइकन पर एक श्रोता सेट करना होगा और उस दृश्य में पास करना होगा जिसे टॉगल किया जाना है।
infoIcon.setOnClickListener { toggleCardBody(root.personEntryBody) }
यदि दृश्य टॉगल किया गया है, तो इसे शुरू में बंद करने के लिए सेट करने के लिए हम कक्षा के भीतर एक चर भी सेट करते हैं।
private var isToggled = false
विस्तृत एनिमेशन को टॉगल करें
हमारे लेआउट में, हमने personEntryBody
. की ऊंचाई निर्धारित की है करने के लिए 0dp
।
इस ओपन को टॉगल करने के लिए हमें यह जानने की जरूरत है कि इसे सेट करने के लिए नई ऊंचाई, एनीमेशन कितना लंबा होना चाहिए, और एनीमेशन के प्रत्येक पल में यह कितनी ऊंचाई होनी चाहिए।
फिर हमें isToggled
. सेट करना होगा इसके विपरीत, और सुनिश्चित करें कि जब दोबारा टैप किया जाता है तो यह विपरीत होता है।
private fun toggleCardBody(body: View) {
body.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
val maxHeight = body.measuredHeight + body.paddingTop + body.paddingBottom
val startHeight = if (isToggled) maxHeight else 0
val targetHeight = if (isToggled) 0 else maxHeight
val expandAnimator = ValueAnimator
.ofInt(startHeight, targetHeight)
.setDuration(200)
expandAnimator.addUpdateListener {
val value = it.animatedValue as Int
body.layoutParams.height = value
body.requestLayout()
}
expandAnimator.doOnEnd {
isToggled = !isToggled
}
expandAnimator.start()
}
चूंकि जब दृश्य शुरू में खींचा जाता है तो ऊंचाई 0 होती है, हमें इसके लेआउट को फिर से मापकर इसके नए आकार की गणना करनी चाहिए।
जैसा कि Android व्यू लेआउट डॉक्स में वर्णित है, हम measure()
. का उपयोग कर सकते हैं प्रत्येक बार जानकारी आइकन टैप किए जाने पर फिर से मापने के लिए हमने दृश्य को असाइन किए गए लेआउट पैरामीटर के साथ।
अधिकतम ऊंचाई की गणना करने के लिए हमें इसमें ऊपर और नीचे पैडिंग को मैन्युअल रूप से जोड़ना होगा, क्योंकि ये मापी गई ऊंचाई में शामिल नहीं हैं।
isToggled
के आधार पर तब हमें पता चलता है कि हम 0 से शुरू कर रहे हैं या विस्तारित अधिकतम ऊंचाई से शुरू कर रहे हैं, और इसलिए विरोधी लक्ष्य ऊंचाई।
हम प्रारंभिक मूल्य से लक्ष्य अंत मूल्य तक जाने के लिए एक वैल्यू एनिमेटर का उपयोग करते हैं, और अवधि को एमएस में सेट करते हैं। यह अवधि विशुद्ध रूप से UX अनुभव के लिए बाद में मैन्युअल परीक्षण पर आधारित है।
ValueAnimator
.ofInt(startHeight, targetHeight)
.setDuration(200)
हम अपडेट श्रोता के साथ अवधि को ऊंचाई से जोड़ते हैं, प्रत्येक अपडेट के बाद एक नया लेआउट तैयार करने का अनुरोध करते हैं और हर बार ऊंचाई समायोजित करते हैं।
expandAnimator.addUpdateListener {
val value = it.animatedValue as Int
body.layoutParams.height = value
body.requestLayout()
}
expandAnimator.doOnEnd {
isToggled = !isToggled
}
expandAnimator.start()
जैसा कि हम कोटलिन का उपयोग कर रहे हैं, हम androidx
. भी जोड़ते हैं हमारे build.gradle
. पर लाइब्रेरी इसके doOnEnd
. से लाभ उठाने के लिए विस्तार। यह हमें बहुत आसानी से isToggled
. को उलटने की अनुमति देता है चर।
अंत में हम अपना एनीमेशन शुरू करते हैं! हमारे पास पहले से ही एक निकाय है जो एक आइकन स्पर्श पर फैलता और सिकुड़ता है!
स्मूथ एनिमेशन
जबकि हमारा एनीमेशन तकनीकी रूप से काम करता है, एक अच्छा अतिरिक्त कदम एक इंटरपोलेटर जोड़ना है ताकि आंदोलन अधिक स्वाभाविक महसूस हो।
expandAnimator.interpolator = FastOutSlowInInterpolator()
हमारी पहुंच बढ़ाना
उम्मीद है कि हमारे a11y उपयोगकर्ताओं की मदद करने के लिए हम दो अंतिम चीज़ें जोड़ेंगे।
पहले हम AccessibilityEvent
. का उपयोग करके नेविगेशन में सहायता कर सकते हैं ।
expandAnimator.doOnEnd {
if (!isToggled) body.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
isToggled = !isToggled
}
इसका मतलब यह है कि जब एनीमेशन बंद से खुले में चलता है, तो फोकस तुरंत शरीर के पहले आइटम पर फोकस पर पहुंच जाएगा, इस मामले में विवरण। लेआउट में, हम जानकारी आइकन क्रिया का विवरण सेट करते हैं, लेकिन हो सकता है कि हम उपयोगकर्ता के लिए अगले आइटम पर जाने के लिए दृश्य संकेतक पर भरोसा करने में सक्षम न हों, हम उनके लिए इसे संभाल सकते हैं।
दूसरा हम विभिन्न फ़ॉन्ट आकारों के लिए अनुमति देते हैं। मापी गई ऊंचाई measure()
. से लौटाई गई डिवाइस एक्सेसिबिलिटी सेटिंग्स में सेट किए गए फ़ॉन्ट स्केलिंग के लिए जिम्मेदार नहीं है, और इसलिए जब बड़े पैमाने पर विवरण के निचले हिस्से को काट दिया जाएगा क्योंकि यह फिट होने के लिए बहुत बड़ा है।
हम फॉन्ट स्केल को प्रोग्रामेटिक रूप से एक्सेस कर सकते हैं, और इसके आधार पर अपनी ऊंचाई को माप सकते हैं। हम इसे एक पूर्णांक में बदलते हैं क्योंकि फ़ॉन्ट स्केल के परिणामस्वरूप एक फ्लोट हो सकता है जो लेआउट ऊंचाई के रूप में काम नहीं करेगा।
val a11yFontScale = body.context.resources.configuration.fontScale
val maxHeight = ((body.measuredHeight + body.paddingTop + body.paddingBottom) * a11yFontScale).toInt()
समाप्त!
और वहां हमारे पास है, हम अपने अंतिम एनीमेशन पर आ गए हैं! बस कुछ अतिरिक्त पंक्तियों के साथ हमने इसकी a11y कवरेज को बहुत बढ़ा दिया है और कोटलिन और Android बैज को प्रकट करने वाला एक सहज विस्तार वाला अनुभाग है?
पढ़ने के लिए धन्यवाद?
यहाँ कुछ अन्य चीज़ें हैं जो मैंने हाल ही में लिखी हैं:
- CodeceptJS E2E टेस्ट को कस्टमाइज़ करना
- जेस्ट और एंजाइम II के साथ परीक्षण प्रतिक्रिया
उपयोगी अतिरिक्त
- Android के लिए KTX को एक्सप्लोर करने पर जो बिर्च की शानदार androidx पोस्ट
- एंड्रॉइड एक्सेसिबिलिटी ट्यूटोरियल:प्रारंभ करना