एक सुंदर और आकर्षक यूआई महत्वपूर्ण है। इसलिए, एंड्रॉइड के लिए, डिजाइन तत्वों के सुंदर प्रदर्शन के लिए बड़ी संख्या में पुस्तकालय हैं। अक्सर आवेदन में आपको एक संख्या या किसी प्रकार के काउंटर के साथ एक फ़ील्ड दिखाने की आवश्यकता होती है। उदाहरण के लिए, चयनित सूची मदों की संख्या या एक महीने के लिए खर्च की राशि के लिए एक काउंटर। बेशक, इस तरह के कार्य को नियमित रूप से 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
) भी है।