एक सुंदर और आकर्षक यूआई महत्वपूर्ण है। इसलिए, एंड्रॉइड के लिए, डिजाइन तत्वों के सुंदर प्रदर्शन के लिए बड़ी संख्या में पुस्तकालय हैं। अक्सर आवेदन में आपको एक संख्या या किसी प्रकार के काउंटर के साथ एक फ़ील्ड दिखाने की आवश्यकता होती है। उदाहरण के लिए, चयनित सूची मदों की संख्या या एक महीने के लिए खर्च की राशि के लिए एक काउंटर। बेशक, इस तरह के कार्य को नियमित रूप से TextView की मदद से आसानी से हल किया जा सकता है, लेकिन आप इसे आसानी से हल कर सकते हैं और संख्या बदलने का एनीमेशन जोड़ सकते हैं:

डेमो वीडियो यूट्यूब पर उपलब्ध हैं।
लेख यह सब कैसे लागू करने के बारे में बात करेगा।
एक स्थिर अंक
प्रत्येक संख्या के लिए एक वेक्टर छवि है, उदाहरण के लिए, 8 के लिए यह res/drawable/viv_vd_pathmorph_digits_eight.xml :
 <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="@dimen/viv_digit_size" android:height="@dimen/viv_digit_size" android:viewportHeight="1" android:viewportWidth="1"> <group android:translateX="@dimen/viv_digit_translateX" android:translateY="@dimen/viv_digit_translateY"> <path android:name="iconPath" android:pathData="@string/viv_path_eight" android:strokeColor="@color/viv_digit_color_default" android:strokeWidth="@dimen/viv_digit_strokewidth"/> </group> </vector> 
संख्या 0-9 के अलावा, माइनस साइन इमेज ( viv_vd_pathmorph_digits_minus.xml ) और एक रिक्त छवि ( viv_vd_pathmorph_digits_nth.xml ), जो एनीमेशन के दौरान संख्या के लुप्त होने का प्रतीक होगी, भी आवश्यक हैं।
XML छवि फ़ाइलें केवल android:pathData में भिन्न होती हैं android:pathData । अन्य सभी विशेषताएँ अलग-अलग संसाधनों के माध्यम से सुविधा के लिए निर्धारित हैं और सभी वेक्टर छवियों के लिए समान हैं।
0-9 नंबर के चित्र यहां लिए गए थे।
संक्रमण एनीमेशन
वर्णित वेक्टर छवियां स्थिर छवियां हैं। एनिमेशन के लिए, आपको एनिमेटेड वेक्टर इमेज ( <animated-vector> ) को जोड़ना होगा। उदाहरण के लिए, संख्या 2 को चेतन करने के लिए, फ़ाइल को 5 नंबर पर जोड़ने res/drawable/viv_avd_pathmorph_digits_2_to_5.xml करने res/drawable/viv_avd_pathmorph_digits_2_to_5.xml जोड़ें:
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" android:drawable="@drawable/viv_vd_pathmorph_digits_zero"> <target android:name="iconPath"> <aapt:attr name="android:animation"> <objectAnimator android:duration="@integer/viv_animation_duration" android:propertyName="pathData" android:valueFrom="@string/viv_path_two" android:valueTo="@string/viv_path_five" android:valueType="pathType"/> </aapt:attr> </target> </animated-vector> 
यहां, सुविधा के लिए, हम एक अलग संसाधन के माध्यम से एनीमेशन की अवधि निर्धारित करते हैं। कुल में, हमारे पास 12 स्थिर छवियां हैं (0 - 9 + "माइनस" + "शून्य"), उनमें से प्रत्येक दूसरों में से किसी में भी एनिमेटेड हो सकता है। यह पता चला है कि पूर्णता के लिए, 12 * 11 = 132 एनीमेशन फ़ाइलों की आवश्यकता होती है। वे केवल विशेषताओं android:valueFrom में android:valueFrom होंगे android:valueFrom और android:valueTo , और उन्हें मैन्युअल रूप से बनाना एक विकल्प नहीं है। इसलिए, हम एक साधारण जनरेटर लिखेंगे:
एनीमेशन फ़ाइल जनरेटर import java.io.File import java.io.FileWriter fun main(args: Array<String>) { val names = arrayOf( "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "nth", "minus" ) fun getLetter(i: Int) = when (i) { in 0..9 -> i.toString() 10 -> "n" 11 -> "m" else -> null!! } val dirName = "viv_out" File(dirName).mkdir() for (from in 0..11) { for (to in 0..11) { if (from == to) continue FileWriter(File(dirName, "viv_avd_pathmorph_digits_${getLetter(from)}_to_${getLetter(to)}.xml")).use { it.write(""" <?xml version="1.0" encoding="utf-8"?> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" android:drawable="@drawable/viv_vd_pathmorph_digits_zero"> <target android:name="iconPath"> <aapt:attr name="android:animation"> <objectAnimator android:duration="@integer/viv_animation_duration" android:propertyName="pathData" android:valueFrom="@string/viv_path_${names[from]}" android:valueTo="@string/viv_path_${names[to]}" android:valueType="pathType"/> </aapt:attr> </target> </animated-vector> """.trimIndent()) } } } } 
 सब एक साथ
अब आपको स्थिर वेक्टर छवियों और संक्रमण एनिमेशन को एक <animated-selector> फ़ाइल में कनेक्ट करने की आवश्यकता है, जो एक नियमित <selector> , वर्तमान स्थिति के आधार पर छवियों में से एक को प्रदर्शित करता है। इस res/drawable/viv_asl_pathmorph_digits.xml रिसोर्स ( res/drawable/viv_asl_pathmorph_digits.xml ) में इमेज स्टेट्स की घोषणा और उनके बीच बदलाव शामिल हैं।
राज्य एक छवि और एक राज्य विशेषता (इस मामले में, app:viv_state_three ) के साथ टैग का उपयोग करके सेट किए जाते हैं जो इस छवि को परिभाषित करता है। प्रत्येक राज्य के पास एक id , जिसका उपयोग वांछित संक्रमण एनीमेशन को निर्धारित करने के लिए किया जाता है:
 <item android:id="@+id/three" android:drawable="@drawable/viv_vd_pathmorph_digits_three" app:viv_state_three="true" /> 
राज्य विशेषताओं को res/values/attrs.xml में सेट किया जाता है:
 <resources> <declare-styleable name="viv_DigitState"> <attr name="viv_state_zero" format="boolean" /> <attr name="viv_state_one" format="boolean" /> <attr name="viv_state_two" format="boolean" /> <attr name="viv_state_three" format="boolean" /> <attr name="viv_state_four" format="boolean" /> <attr name="viv_state_five" format="boolean" /> <attr name="viv_state_six" format="boolean" /> <attr name="viv_state_seven" format="boolean" /> <attr name="viv_state_eight" format="boolean" /> <attr name="viv_state_nine" format="boolean" /> <attr name="viv_state_nth" format="boolean" /> <attr name="viv_state_minus" format="boolean" /> </declare-styleable> </resources> 
राज्यों के बीच संक्रमण के एनिमेशन <transition> टैग के साथ <animated-vector> संकेत द्वारा निर्धारित किए जाते हैं, जो संक्रमण का प्रतीक है, साथ ही प्रारंभिक और अंतिम राज्य की id :
 <transition android:drawable="@drawable/viv_avd_pathmorph_digits_6_to_2" android:fromId="@id/six" android:toId="@id/two" /> 
res/drawable/viv_asl_pathmorph_digits.xml की सामग्री बहुत समान हैं, और इसे बनाने के लिए एक जनरेटर का भी उपयोग किया गया था। इस आकर्षित करने योग्य संसाधन में 12 राज्य और उनके बीच 132 संक्रमण हैं।
CustomView
अब जब हमारे पास एक drawable है जो हमें एक अंक को प्रदर्शित करने और इसके परिवर्तन को चेतन करने की अनुमति देता है, तो हमें एक VectorIntegerView बनाने की आवश्यकता है जिसमें कई अंक होंगे और एनिमेशन को नियंत्रित करेंगे। RecyclerView को आधार के रूप में चुना गया था, क्योंकि संख्या में अंकों की संख्या एक चर मान है, और एक पंक्ति में तत्वों (संख्याओं) की एक चर संख्या प्रदर्शित करने के लिए RecyclerView Android में सबसे अच्छा तरीका है। इसके अलावा, RecyclerView आपको ItemAnimator माध्यम से आइटम एनिमेशन को नियंत्रित करने की अनुमति देता है।
DigitAdapter और DigitViewHolder
आपको एक DigitViewHolder वाला एक DigitViewHolder बनाकर शुरू करना होगा। View तरह के एक DigitViewHolder View android:src="@drawable/viv_asl_pathmorph_digits" साथ एकल DigitViewHolder में शामिल होगा android:src="@drawable/viv_asl_pathmorph_digits" । ImageView में वांछित अंक प्रदर्शित करने के लिए, mImageView.setImageState(state, true); विधि का उपयोग किया जाता है mImageView.setImageState(state, true); । राज्य state सरणी ऊपर परिभाषित viv_DigitState राज्य विशेषताओं का उपयोग करके प्रदर्शित अंक के आधार पर बनाई गई है।
`ImageView` में वांछित अंक प्रदर्शित करें private static final int[] ATTRS = { R.attr.viv_state_zero, R.attr.viv_state_one, R.attr.viv_state_two, R.attr.viv_state_three, R.attr.viv_state_four, R.attr.viv_state_five, R.attr.viv_state_six, R.attr.viv_state_seven, R.attr.viv_state_eight, R.attr.viv_state_nine, R.attr.viv_state_nth, R.attr.viv_state_minus, }; void setDigit(@IntRange(from = 0, to = VectorIntegerView.MAX_DIGIT) int digit) { int[] state = new int[ATTRS.length]; for (int i = 0; i < ATTRS.length; i++) { if (i == digit) { state[i] = ATTRS[i]; } else { state[i] = -ATTRS[i]; } } mImageView.setImageState(state, true); } 
 DigitAdapter एडेप्टर एडाप्टर DigitAdapter बनाने और वांछित DigitViewHolder में वांछित अंक प्रदर्शित करने के लिए DigitViewHolder ।
एक नंबर को दूसरे में बदलने के सही एनीमेशन के लिए, DiffUtil उपयोग किया जाता है। इसके साथ, दसियों की रैंक दसियों, सैकड़ों से सैकड़ों, लाखों से करोड़ों के दसियों के रैंक के लिए एनिमेटेड है, और इसी तरह। माइनस सिंबल हमेशा अपने आप बना रहता है और केवल खाली छवि ( viv_vd_pathmorph_digits_nth.xml ) में बदलकर प्रकट या गायब हो सकता है।
ऐसा करने के लिए, DiffUtil.Callback मेथड true यदि संख्याओं के समान अंकों की तुलना की जाती है। माइनस एक विशेष श्रेणी है, और पिछली संख्या से माइनस नए नंबर से माइनस के बराबर है।
areContentsTheSame विधि पिछले और नए नंबरों में कुछ पदों पर वर्णों की तुलना करती है। DigitAdapter में ही कार्यान्वयन देखा जा सकता है।
DigitItemAnimator
संख्या में परिवर्तन का एनीमेशन, अर्थात्, परिवर्तन, उपस्थिति और संख्याओं के लापता होने पर, RecyclerView - DigitItemAnimator लिए एक विशेष एनिमेटर द्वारा नियंत्रित किया जाएगा। एनिमेशन की अवधि निर्धारित करने के लिए, समान integer संसाधन का उपयोग ऊपर दिए गए <animated-vector> रूप में किया जाता है:
 private final int animationDuration; DigitItemAnimator(@NonNull Resources resources) { animationDuration = resources.getInteger(R.integer.viv_animation_duration); } @Override public long getMoveDuration() { return animationDuration; } @Override public long getAddDuration() { return animationDuration; } @Override public long getRemoveDuration() { return animationDuration; } @Override public long getChangeDuration() { return animationDuration; } 
DigitItemAnimator का थोक DigitItemAnimator तरीकों से DigitItemAnimator है। किसी अंक ( animateAdd विधि) की उपस्थिति का एनीमेशन एक खाली छवि से वांछित अंक या माइनस साइन में संक्रमण के रूप में किया जाता है। गायब एनीमेशन ( animateRemove विधि) को प्रदर्शित अंक या माइनस साइन से एक रिक्त छवि में संक्रमण के रूप में किया जाता है।
एक अंक परिवर्तन एनीमेशन करने के लिए, पिछले प्रदर्शित अंक पर जानकारी पहले recordPreLayoutInformation विधि को ओवरराइड करके संग्रहीत की जाती है। फिर, animateChange परिवर्तन विधि में, पिछले प्रदर्शित अंक से नए पर संक्रमण किया जाता है।
RecyclerView.ItemAnimator को ओवरराइडिंग एनीमेशन विधियों की आवश्यकता होती है जो एनीमेशन के अंत का प्रतीक करने वाले तरीकों को लागू करना चाहिए। इसलिए, प्रत्येक animateAdd , animateRemove और animateChange विधियों में, एनीमेशन की अवधि के बराबर देरी के साथ संबंधित विधि के लिए एक कॉल है। उदाहरण के लिए, animateAdd विधि @integer/viv_animation_duration बराबर विलंब के साथ dispatchAddFinished किए गए विधि को कॉल @integer/viv_animation_duration :
 @Override public boolean animateAdd(final RecyclerView.ViewHolder holder) { final DigitAdapter.DigitViewHolder digitViewHolder = (DigitAdapter.DigitViewHolder) holder; int a = digitViewHolder.d; digitViewHolder.setDigit(VectorIntegerView.DIGIT_NTH); digitViewHolder.setDigit(a); holder.itemView.postDelayed(new Runnable() { @Override public void run() { dispatchAddFinished(holder); } }, animationDuration); return false; } 
VectorIntegerView
CustomView बनाने से पहले, आपको इसकी xml विशेषताएँ परिभाषित करने की आवश्यकता है। ऐसा करने के लिए, res/values/attrs.xml <declare-styleable> जोड़ें:
 <declare-styleable name="VectorIntegerView"> <attr name="viv_vector_integer" format="integer" /> <attr name="viv_digit_color" format="color" /> </declare-styleable> 
बनाए गए VectorIntegerView अनुकूलन के लिए 2 xml विशेषताएँ होंगी:
- viv_vector_integerबनाते समय प्रदर्शित संख्या (डिफ़ॉल्ट रूप से 0) को- viv_vector_integer।
- viv_digit_colorसंख्याओं का रंग (डिफ़ॉल्ट रूप से काला)।
अन्य VectorIntegerView पैरामीटर को एप्लिकेशन में संसाधनों को ओवरराइड करके बदला जा सकता है (जैसा कि डेमो एप्लिकेशन में किया जाता है):
- @integer/viv_animation_durationएनीमेशन की अवधि (डिफ़ॉल्ट रूप से 400ms) निर्धारित करता है।
- @dimen/viv_digit_sizeएक अंक का आकार (डिफ़ॉल्ट रूप से- 24dp) निर्धारित करता है।
- @dimen/viv_digit_translateXक्षैतिज रूप से उन्हें संरेखित करने के लिए अंकों की सभी वेक्टर छवियों पर लागू होता है।
- @dimen/viv_digit_translateYको अनुलंब रूप से संरेखित करने के लिए अंकों की सभी वेक्टर छवियों पर लागू किया जाता है।
- @dimen/viv_digit_strokewidthसभी अंक वेक्टर छवियों पर लागू होता है।
- @dimen/viv_digit_margin_horizontalसभी दृश्य अंकों (- DigitViewHolder) (डिफ़ॉल्ट रूप से- DigitViewHolder) पर लागू होता है। यह संख्याओं के बीच रिक्त स्थान बनाने के लिए आवश्यक है, क्योंकि संख्याओं की वेक्टर छवियां वर्गाकार हैं।
ओवरराइड किए गए संसाधनों को एप्लिकेशन में सभी VectorIntegerView लागू किया जाएगा।
इन सभी मापदंडों को संसाधनों के माध्यम से सेट किया जाता है, क्योंकि VectorDrawable आकार देना या कोड के माध्यम से VectorDrawable एनीमेशन की अवधि असंभव है।
XML मार्कअप में VectorIntegerView जोड़ना इस तरह दिखता है:
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.qwert2603.vector_integer_view.VectorIntegerView android:id="@+id/vectorIntegerView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp" app:viv_digit_color="#ff8000" app:viv_vector_integer="14" /> </FrameLayout> 
इसके बाद, आप BigInteger पास करके कोड में प्रदर्शित संख्या बदल सकते हैं:
 final VectorIntegerView vectorIntegerView = findViewById(R.id.vectorIntegerView); vectorIntegerView.setInteger( vectorIntegerView.getInteger().add(BigInteger.ONE),  true ); 
सुविधा के लिए, कई प्रकार के long संचारित करने की एक विधि है:
 vectorIntegerView.setInteger(1918L, false); 
यदि false को animated रूप false पारित किया जाता है, तो notifyDataSetChanged लिए notifyDataSetChanged विधि को कॉल किया जाएगा, और नया नंबर एनिमेशन के बिना प्रदर्शित किया जाएगा।
जब आप VectorIntegerView फिर से VectorIntegerView प्रदर्शित संख्या को onSaveInstanceState और onRestoreInstanceState का उपयोग करके सहेजा जाता है।
स्रोत कोड
स्रोत कोड github (पुस्तकालय निर्देशिका) पर उपलब्ध है। वहाँ भी एक डेमो अनुप्रयोग है VectorIntegerView उपयोग कर VectorIntegerView (ऐप डायरेक्टरी) है।
एक डेमो APK ( minSdkVersion 21 ) भी है।