Android: एनीमेशन का विस्तार / पतन करें


449

मान लें कि मेरे पास एक लंबवत रैखिक रेखा है:

[v1]
[v2]

डिफ़ॉल्ट रूप से v1 में नेत्रहीन = चला गया है। मैं एक विस्तार एनीमेशन के साथ v1 दिखाना चाहता हूं और उसी समय v2 को नीचे धकेलूंगा।

मैंने कुछ इस तरह की कोशिश की:

Animation a = new Animation()
{
    int initialHeight;

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final int newHeight = (int)(initialHeight * interpolatedTime);
        v.getLayoutParams().height = newHeight;
        v.requestLayout();
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        initialHeight = height;
    }

    @Override
    public boolean willChangeBounds() {
        return true;
    }
};

लेकिन इस समाधान के साथ, जब एनीमेशन शुरू होता है, तो मुझे पलक होती है। मुझे लगता है कि एनीमेशन लागू होने से पहले यह v1 पूर्ण आकार प्रदर्शित करने के कारण होता है।

जावास्क्रिप्ट के साथ, यह jQuery की एक पंक्ति है! Android के साथ ऐसा करने का कोई सरल तरीका?

जवाबों:


734

मैं देखता हूं कि यह प्रश्न लोकप्रिय हो गया है इसलिए मैं अपना वास्तविक समाधान पोस्ट करता हूं। मुख्य लाभ यह है कि आपको एनीमेशन को लागू करने के लिए विस्तारित ऊंचाई को जानने की आवश्यकता नहीं है और एक बार जब दृश्य का विस्तार हो जाता है, तो यह ऊंचाई को बदल देता है यदि सामग्री बदल जाती है। यह मेरे लिए बहुत अच्छा काम करता है।

public static void expand(final View v) {
    int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(), View.MeasureSpec.EXACTLY);
    int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    v.measure(matchParentMeasureSpec, wrapContentMeasureSpec);
    final int targetHeight = v.getMeasuredHeight();

    // Older versions of android (pre API 21) cancel animations for views with a height of 0.
    v.getLayoutParams().height = 1;
    v.setVisibility(View.VISIBLE);
    Animation a = new Animation()
    {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            v.getLayoutParams().height = interpolatedTime == 1
                    ? LayoutParams.WRAP_CONTENT
                    : (int)(targetHeight * interpolatedTime);
            v.requestLayout();
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };

    // Expansion speed of 1dp/ms
    a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));
    v.startAnimation(a);
}

public static void collapse(final View v) {
    final int initialHeight = v.getMeasuredHeight();

    Animation a = new Animation()
    {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            if(interpolatedTime == 1){
                v.setVisibility(View.GONE);
            }else{
                v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
                v.requestLayout();
            }
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };

    // Collapse speed of 1dp/ms
    a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
    v.startAnimation(a);
}

जैसा कि टिप्पणियों में @ जेफरसन ने उल्लेख किया है, आप एनीमेशन की अवधि (और इसलिए गति) को बदलकर एक चिकनी एनीमेशन प्राप्त कर सकते हैं। वर्तमान में, इसे 1dp / ms की गति से सेट किया गया है


13
v.measure (मेज़स्पेक्ट.makeMeasureSpec (LayoutParams.MATCH_PARENT, मेज़स्पेक्ट .EXACTLY), मेज़स्पेक.makeMeasureSpec (LayoutParams.WRAP_CONTENT, मेज़पेक .EXACTLY)); कुछ मामलों में (मेरी - सूची दृश्य) यह बेमेल गलत targtetHeight मान की ओर जाता है
जॉनी डो

12
@ टोम एस्ट्रेस यह काम करता है, लेकिन बहुत आसानी से नहीं। क्या इसे सुचारू रूप से बनाने के लिए कोई अतिरिक्त काम है?
acntwww

9
@acntwww आप कुछ पहलू से अवधि गुणा, 4. तरह एक सुचारू रूप से एनीमेशन प्राप्त कर सकते हैंa.setDuration(((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density)) * 4)
जेफरसन हेनरिक सी सोरेस

10
@ एलियो, आयात android.view.animation.Transformation;
जोमिया

5
बहुत अच्छा काम करता है! मुझे मापित ऊँचाई के साथ समस्या थी क्योंकि मैं एक निश्चित dp तत्व का विस्तार करना चाहता था, इसलिए मैंने माप को बदल दिया v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));और v.getLayoutParams().height = interpolatedTime == 1 ? targetHeight : (int)(targetHeight * interpolatedTime);यह मेरे लिए काम कर गया!
vkislicins

140

मैं वह करने की कोशिश कर रहा था जो मुझे लगता है कि एक बहुत ही समान एनीमेशन था और एक सुरुचिपूर्ण समाधान मिला। यह कोड मानता है कि आप हमेशा 0-> एच या एच-> 0 (एच अधिकतम ऊंचाई होने) से जा रहे हैं। तीन कंस्ट्रक्टर पैरामीटर दृश्य हैं = एनिमेटेड होने के लिए दृश्य (मेरे मामले में, एक वेबव्यू), targetHeight = दृश्य की अधिकतम ऊंचाई, और नीचे = एक बूलियन जो दिशा निर्दिष्ट करता है (सत्य = विस्तार, असत्य = पतन)।

public class DropDownAnim extends Animation {
    private final int targetHeight;
    private final View view;
    private final boolean down;

    public DropDownAnim(View view, int targetHeight, boolean down) {
        this.view = view;
        this.targetHeight = targetHeight;
        this.down = down;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        int newHeight;
        if (down) {
            newHeight = (int) (targetHeight * interpolatedTime);
        } else {
            newHeight = (int) (targetHeight * (1 - interpolatedTime));
        }
        view.getLayoutParams().height = newHeight;
        view.requestLayout();
    }

    @Override
    public void initialize(int width, int height, int parentWidth,
            int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
    }

    @Override
    public boolean willChangeBounds() {
        return true;
    }
}

5
कोड में एक टाइपो है: "initalize" विधि का नाम "इनिशियलाइज़" होना चाहिए या इसे कॉल नहीं किया जाएगा। ;) मैं भविष्य में @ ऑवरराइड का उपयोग करने की सलाह दूंगा ताकि इस प्रकार के टाइपो को कंपाइलर द्वारा पकड़ा जाए।
लोर्ने लालटेते

4
मैं निम्नलिखित कर रहा हूं: "DropDownAnim anim = new DropDownAnim (grid_titulos_atual, GRID_HEIGHT, true); anim.setDuration (500); anim.start ();" लेकिन यह काम नहीं कर रहा है। मैंने कुछ ब्रेकप्वाइंट्स को applyTransformation पर रखा, लेकिन वे कभी नहीं पहुंच रहे हैं
पाउलो सीज़र

5
ऑप्स, यह काम करने के लिए मिला, यह view.startAnimation (a) ... प्रदर्शन बहुत अच्छा नहीं है, लेकिन यह काम करता है :)
पाउलो सेसर

3
@IamStalker उस स्थिति में, आपको संभवतः दो चर के साथ आरंभ करना चाहिए, शुरुआत और समापन। फिर बदलकर: यदि (नीचे) {newHeight = (int) (((EndHeight-startHeight) * interpolatedTime) + startHeight); } और {newHeight = (int) (((EndHeight-startHeight) * (1 - इंटरपोलिएटटाइम)) + startHeight); }
सेठ नेल्सन

3
@ मुझे लगता है कि newHeight बस (int) हो सकती है (((targetHeight -startingHeight) * interpolatedTime) + startHeight), कोई बात नहीं दिशा, जब तक startHeight को इनिशियलाइज़ () में सेट नहीं किया जाता है।
जियोगोस काइलाफस

138

मैं आज उसी समस्या से लड़ रहा हूं और मुझे लगता है कि इस प्रश्न का वास्तविक समाधान यही है

<LinearLayout android:id="@+id/container"
android:animateLayoutChanges="true"
...
 />

आपको इस संपत्ति को उन सभी शीर्ष लेआउट के लिए सेट करना होगा, जो शिफ्ट में शामिल हैं। यदि आप अब एक लेआउट की दृश्यता को GONE पर सेट करते हैं, तो दूसरा स्थान ले लेगा क्योंकि गायब होने वाला इसे जारी कर रहा है। एक डिफ़ॉल्ट एनीमेशन होगा जो किसी प्रकार का "फ़ेडिंग आउट" है, लेकिन मुझे लगता है कि आप इसे बदल सकते हैं - लेकिन पिछले एक जो मैंने अभी तक परीक्षण नहीं किया है।


2
+1, अब मैं गति की खोज कर रहा हूं: चेतन लयआउट की अवधि
तुषार पांडे


यह बैक बटन दबाने के बाद काम नहीं करता है। कोई सुझाव?
हसन तारेक

4
यह एनीमेशन के विस्तार के लिए पूरी तरह से काम करता है, लेकिन माता-पिता के लेआउट के हटने के बाद एनीमेशन का पतन होता है।
चमक_जोसेफ

3
@shine_joseph हाँ, मैं इसे एक रिसाइकिलव्यू के अंदर इस्तेमाल कर रहा हूँ और जब
ढहना

65

मैंने @LenaYan का समाधान लिया, जो मेरे लिए ठीक से काम नहीं कर रहा था ( क्योंकि यह दृश्य को 0 में बदलने से पहले ऊँचाई को बदल रहा था और / या विस्तार कर रहा था ) और कुछ परिवर्तन किए।

अब यह बहुत अच्छा काम करता है , व्यू की पिछली ऊंचाई लेकर और इस आकार के साथ विस्तार करना शुरू करता है। कोलैपिंग समान है।

आप बस नीचे दिए गए कोड को कॉपी और पेस्ट कर सकते हैं:

public static void expand(final View v, int duration, int targetHeight) {

    int prevHeight  = v.getHeight();

    v.setVisibility(View.VISIBLE);
    ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            v.getLayoutParams().height = (int) animation.getAnimatedValue();
            v.requestLayout();
        }
    });
    valueAnimator.setInterpolator(new DecelerateInterpolator());
    valueAnimator.setDuration(duration);
    valueAnimator.start();
}

public static void collapse(final View v, int duration, int targetHeight) {
    int prevHeight  = v.getHeight();
    ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);
    valueAnimator.setInterpolator(new DecelerateInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            v.getLayoutParams().height = (int) animation.getAnimatedValue();
            v.requestLayout();
        }
    });
    valueAnimator.setInterpolator(new DecelerateInterpolator());
    valueAnimator.setDuration(duration);
    valueAnimator.start();
}

उपयोग:

//Expanding the View
   expand(yourView, 2000, 200);

// Collapsing the View     
   collapse(yourView, 2000, 100);

काफी आसान!

प्रारंभिक कोड के लिए धन्यवाद LenaYan!


हालांकि यह काम करता है, यह डेवलपर सेटिंग्स (एनीमेशन अवधि) पर निर्भर करता है। यदि यह अक्षम है, तो कोई एनीमेशन नहीं दिखाया जाएगा।
कूलमैन्ड

हां, लेकिन यह एक समस्या हो सकती है या नहीं। आपके आवेदन पर निर्भर करता है। उदाहरण के लिए, आप आसानी से एनीमेशन अवधि को सरल बदलावों के साथ विस्तारित / ध्वस्त आकार के आनुपातिक कर सकते हैं। एक बसने योग्य एनीमेशन अवधि होने से आपको थोड़ी अधिक स्वतंत्रता मिलती है।
गेराल्डो नेटो

काम नहीं कर रहा एनीमेशन का विस्तार करें। यह पतन एनीमेशन की तरह दिखता है।
अहमदुल्लाह सैकत

39

विस्तार के लिए निम्नलिखित स्केलिंग कारकों के साथ एक स्केल एनीमेशन का उपयोग करना एक विकल्प है:

ScaleAnimation anim = new ScaleAnimation(1, 1, 0, 1);

और ढहने के लिए:

ScaleAnimation anim = new ScaleAnimation(1, 1, 1, 0);

एनीमेशन कैसे शुरू करें .. View.startAnimation (anim); काम नहीं लगता
महेंद्रन

यह अतिशयोक्ति है कि मैं एनीमेशन कैसे शुरू करता हूं। क्या अन्य एनिमेशन आपके लिए काम करते हैं?
क्रिस्टोफ

1
इस दृष्टिकोण के साथ चला गया, एक आकर्षण की तरह काम करता है और इसे लागू करने की आवश्यकता नहीं है जो पहले से ही लागू हो चुका है।
erbsman

15
यह एनीमेशन के दौरान नीचे के विचारों को नीचे नहीं धकेलता है और ऐसा प्रतीत होता है मानो यह 0 -> h से एनिमेटेड दृश्य को खींच रहा है।

5
Btw, देखें एनिमेशन स्केलिंग के लिए महान काम करते हैं: oView.animate ()। बड़े पैमाने पर (0) लंबवत रूप से ढहने के लिए; oView.animate ()। स्केल (1) खोलने के लिए (ध्यान दें कि यह केवल उपलब्ध sdk 12 और ऊपर है)।
कर्क बी।

27

@ टोम एस्ट्रेस जवाब , लेकिन एंड्रॉइड getMeasuredHeight के प्रति view.measure () को ठीक से उपयोग करने के लिए अपडेट किया गया है, गलत मान देता है!

    // http://easings.net/
    Interpolator easeInOutQuart = PathInterpolatorCompat.create(0.77f, 0f, 0.175f, 1f);

    public static Animation expand(final View view) {
        int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) view.getParent()).getWidth(), View.MeasureSpec.EXACTLY);
        int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        view.measure(matchParentMeasureSpec, wrapContentMeasureSpec);
        final int targetHeight = view.getMeasuredHeight();

        // Older versions of android (pre API 21) cancel animations for views with a height of 0 so use 1 instead.
        view.getLayoutParams().height = 1;
        view.setVisibility(View.VISIBLE);

        Animation animation = new Animation() {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {

               view.getLayoutParams().height = interpolatedTime == 1
                    ? ViewGroup.LayoutParams.WRAP_CONTENT
                    : (int) (targetHeight * interpolatedTime);

            view.requestLayout();
        }

            @Override
            public boolean willChangeBounds() {
                return true;
            }
        };

        animation.setInterpolator(easeInOutQuart);
        animation.setDuration(computeDurationFromHeight(view));
        view.startAnimation(animation);

        return animation;
    }

    public static Animation collapse(final View view) {
        final int initialHeight = view.getMeasuredHeight();

        Animation a = new Animation() {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                if (interpolatedTime == 1) {
                    view.setVisibility(View.GONE);
                } else {
                    view.getLayoutParams().height = initialHeight - (int) (initialHeight * interpolatedTime);
                    view.requestLayout();
                }
            }

            @Override
            public boolean willChangeBounds() {
                return true;
            }
        };

        a.setInterpolator(easeInOutQuart);

        int durationMillis = computeDurationFromHeight(view);
        a.setDuration(durationMillis);

        view.startAnimation(a);

        return a;
    }

    private static int computeDurationFromHeight(View view) {
        // 1dp/ms * multiplier
        return (int) (view.getMeasuredHeight() / view.getContext().getResources().getDisplayMetrics().density);
    }

1
AddHeight और DURATION_MULTIPLIER क्या है?
मिडासफ्लोको

उन लोगों के बारे में भूल गए, AddHeight के मामले में आप अपने विस्तार में अतिरिक्त ऊंचाई की जरूरत है (शायद नहीं) और DURATION_MODIFIER सिर्फ एक गति संशोधक है अगर आप एनिमेशन को गति / धीमा करना चाहते हैं।
एरिक बी

1
बहुत अच्छा काम करता है! अंतिम पंक्ति पर केवल एक शब्द के साथ TextView का उपयोग करते समय एक छोटा अंतराल होता है। और क्या आप बता सकते हैं कि PathInterpolator क्या करता है ..?
yennsarah

सहजतासूत्र पहले एनीमेशन को धीमा करता है, फिर तेज, फिर अंत में बहुत ही स्वाभाविक भावना के लिए धीमा करता है। वे इसके बारे में यहां बात करते हैं easings.net
एरिक बी

1
मैंने आपकी विधि की कोशिश की लेकिन जब भी एनीमेशन समाप्त होता है तो मेरा दृश्य दिखाई नहीं देता है।
अमन वर्मा

26

ठीक है, मैं सिर्फ एक बहुत बदसूरत समाधान पाया:

public static Animation expand(final View v, Runnable onEnd) {
    try {
        Method m = v.getClass().getDeclaredMethod("onMeasure", int.class, int.class);
        m.setAccessible(true);
        m.invoke(
            v,
            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
            MeasureSpec.makeMeasureSpec(((View)v.getParent()).getMeasuredHeight(), MeasureSpec.AT_MOST)
        );
    } catch (Exception e){
        Log.e("test", "", e);
    }
    final int initialHeight = v.getMeasuredHeight();
    Log.d("test", "initialHeight="+initialHeight);

    v.getLayoutParams().height = 0;
    v.setVisibility(View.VISIBLE);
    Animation a = new Animation()
    {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            final int newHeight = (int)(initialHeight * interpolatedTime);
            v.getLayoutParams().height = newHeight;
            v.requestLayout();
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };
    a.setDuration(5000);
    v.startAnimation(a);
    return a;
}

एक बेहतर समाधान का प्रस्ताव करने के लिए स्वतंत्र महसूस करें!


3
+1, यहां तक ​​कि इसे बदसूरत नाम दिया गया है, यह एक ऐसे दृश्य के लिए काम करता है जहां हम अभी तक इसके आकार को नहीं जानते हैं (उदाहरण के मामले में हम एक नए बनाए गए दृश्य को जोड़ रहे हैं (जिसका आकार FILL_PARENT है) और इसे चेतन करना चाहते हैं इस प्रक्रिया में मूल आकार में वृद्धि को शामिल करना शामिल है)।
विट खूदेंको

बीटीडब्ल्यू, ऐसा लगता है कि View.onMeause(widthMeasureSpec, heightMeasureSpec)इनवोकेशन में थोड़ी त्रुटि है , इसलिए चौड़ाई और ऊंचाई के चश्मे की अदला-बदली की जानी चाहिए।
विट खूदेंको

22
public static void expand(final View v, int duration, int targetHeight) {
        v.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        v.getLayoutParams().height = 0;
        v.setVisibility(View.VISIBLE);
        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, targetHeight);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                v.getLayoutParams().height = (int) animation.getAnimatedValue();
                v.requestLayout();
            }
        });
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.setDuration(duration);
        valueAnimator.start();
    }
public static void collapse(final View v, int duration, int targetHeight) {
    ValueAnimator valueAnimator = ValueAnimator.ofInt(0, targetHeight);
    valueAnimator.setInterpolator(new DecelerateInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            v.getLayoutParams().height = (int) animation.getAnimatedValue();
            v.requestLayout();
        }
    });
    valueAnimator.setInterpolator(new DecelerateInterpolator());
    valueAnimator.setDuration(duration);
    valueAnimator.start();
}

1
मेरे पास यह मुद्दा है ... टूटते हुए दृश्य के अंदर की सामग्री विस्तार पर गायब हो रही है। मेरे पास Recycler View है जो इस दृश्य को विस्तारित करने पर गायब हो जाता है। @ लीनायण
अक्षय महाजन

21

यदि आप सभी तरह से विस्तार या पतन नहीं करना चाहते हैं - यहाँ एक सरल ऊंचाई है -

import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;

public class HeightAnimation extends Animation {
    protected final int originalHeight;
    protected final View view;
    protected float perValue;

    public HeightAnimation(View view, int fromHeight, int toHeight) {
        this.view = view;
        this.originalHeight = fromHeight;
        this.perValue = (toHeight - fromHeight);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        view.getLayoutParams().height = (int) (originalHeight + perValue * interpolatedTime);
        view.requestLayout();
    }

    @Override
    public boolean willChangeBounds() {
        return true;
    }
}

उपयोग:

HeightAnimation heightAnim = new HeightAnimation(view, view.getHeight(), viewPager.getHeight() - otherView.getHeight());
heightAnim.setDuration(1000);
view.startAnimation(heightAnim);

13

मैंने टॉम एस्टेरेज़ द्वारा वर्तमान में स्वीकार किए गए उत्तर को अनुकूलित किया , जिसने काम किया लेकिन एक तड़का हुआ था और बहुत चिकनी एनीमेशन नहीं था। मेरा समाधान मूल रूप Animationसे ए के साथ बदल देता है ValueAnimator, जिसे ए के साथ फिट किया जा सकता हैInterpolator विभिन्न प्रभावों जैसे कि ओवरशूट, उछाल, गति, आदि को प्राप्त करने के लिए अपनी पसंद से ।

यह समाधान उन विचारों के साथ बहुत अच्छा काम करता है जिनकी एक गतिशील ऊँचाई होती है (अर्थात उपयोग करते हुए WRAP_CONTENT), क्योंकि यह पहले वास्तविक आवश्यक ऊँचाई को मापता है और फिर उस ऊँचाई को दर्शाता है।

public static void expand(final View v) {
    v.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    final int targetHeight = v.getMeasuredHeight();

    // Older versions of android (pre API 21) cancel animations for views with a height of 0.
    v.getLayoutParams().height = 1;
    v.setVisibility(View.VISIBLE);

    ValueAnimator va = ValueAnimator.ofInt(1, targetHeight);
    va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        public void onAnimationUpdate(ValueAnimator animation) {
            v.getLayoutParams().height = (Integer) animation.getAnimatedValue();
            v.requestLayout();
        }
    });
    va.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationEnd(Animator animation) {
            v.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
        }

        @Override public void onAnimationStart(Animator animation) {}
        @Override public void onAnimationCancel(Animator animation) {}
        @Override public void onAnimationRepeat(Animator animation) {}
    });
    va.setDuration(300);
    va.setInterpolator(new OvershootInterpolator());
    va.start();
}

public static void collapse(final View v) {
    final int initialHeight = v.getMeasuredHeight();

    ValueAnimator va = ValueAnimator.ofInt(initialHeight, 0);
    va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        public void onAnimationUpdate(ValueAnimator animation) {
            v.getLayoutParams().height = (Integer) animation.getAnimatedValue();
            v.requestLayout();
        }
    });
    va.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationEnd(Animator animation) {
            v.setVisibility(View.GONE);
        }

        @Override public void onAnimationStart(Animator animation) {}
        @Override public void onAnimationCancel(Animator animation) {}
        @Override public void onAnimationRepeat(Animator animation) {}
    });
    va.setDuration(300);
    va.setInterpolator(new DecelerateInterpolator());
    va.start();
}

आप तो बस फोन expand( myView );या collapse( myView );


धन्यवाद। आप ऐसी स्थिति भी जोड़ सकते हैं जब न्यूनतम ऊंचाई 0. नहीं है
कूलमाइंड

मैं मेरे लिए linearlayout के लिए काम करता है
रोजर

बस में इस्तेमाल किए गए पैरामेट्स को ठीक किया v.measure()और अब यह पूरी तरह से काम कर रहा है। धन्यवाद!
शैडल उल हसन

9

कोटलिन एक्सटेंशन फ़ंक्शंस का उपयोग करना यह परीक्षण और सबसे छोटा जवाब है

किसी भी दृश्य पर बस चेतनता (विस्तार / पतन) को कॉल करें।

fun View.animateVisibility(setVisible: Boolean) {
    if (setVisible) expand(this) else collapse(this)
}

private fun expand(view: View) {
    view.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
    val initialHeight = 0
    val targetHeight = view.measuredHeight

    // Older versions of Android (pre API 21) cancel animations for views with a height of 0.
    //v.getLayoutParams().height = 1;
    view.layoutParams.height = 0
    view.visibility = View.VISIBLE

    animateView(view, initialHeight, targetHeight)
}

private fun collapse(view: View) {
    val initialHeight = view.measuredHeight
    val targetHeight = 0

    animateView(view, initialHeight, targetHeight)
}

private fun animateView(v: View, initialHeight: Int, targetHeight: Int) {
    val valueAnimator = ValueAnimator.ofInt(initialHeight, targetHeight)
    valueAnimator.addUpdateListener { animation ->
        v.layoutParams.height = animation.animatedValue as Int
        v.requestLayout()
    }
    valueAnimator.addListener(object : Animator.AnimatorListener {
        override fun onAnimationEnd(animation: Animator) {
            v.layoutParams.height = targetHeight
        }

        override fun onAnimationStart(animation: Animator) {}
        override fun onAnimationCancel(animation: Animator) {}
        override fun onAnimationRepeat(animation: Animator) {}
    })
    valueAnimator.duration = 300
    valueAnimator.interpolator = DecelerateInterpolator()
    valueAnimator.start()
}

एक ही जवाब पोस्ट करना चाहता था :) बहुत बुरा यह यहाँ इतना गहरा दफन है।
मुएटज़ेनफ्लो

@muetzenflo यदि अधिक से अधिक लोग उत्तर को बनाए रखते हैं, तो यह सामने आएगा। :)
राजकिरण

मैं इस समाधान को तब तक पसंद करता था जब तक मुझे एहसास नहीं हो जाता कि रैप-कॉन्टेंट की ऊंचाई के साथ कई लाइनों के साथ एक टेक्स्टव्यू है, जब विस्तार किया जाता है, तो टेक्स्टव्यू केवल एक लाइन दिखाएगा। मैं अब ठीक करने की कोशिश कर रहा हूँ
olearyj234

मैंने यह कोशिश की, लेकिन एनीमेशन सुचारू नहीं दिखता है। विस्तार के लिए, संपूर्ण टेक्स्टव्यू एक बार संक्षिप्त रूप में दिखाई देता है और फिर एनीमेशन चलता है। ढहने के लिए, किसी कारणवश, टेक्स्टव्यू ढहने के तुरंत बाद फिर से फैल जाता है। किसी भी विचार मैं गलत क्या कर रहा हूँ?
आचार्य आचार्य

7

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

button.setOnClickListener(v -> expandCollapse(view));

... जो नीचे विधि को बुलाता है और यह बताता है कि प्रत्येक onClick () के बाद क्या करना है ...

public static void expandCollapse(View view) {

    boolean expand = view.getVisibility() == View.GONE;
    Interpolator easeInOutQuart = PathInterpolatorCompat.create(0.77f, 0f, 0.175f, 1f);

    view.measure(
        View.MeasureSpec.makeMeasureSpec(((View) view.getParent()).getWidth(), View.MeasureSpec.EXACTLY),
        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
    );

    int height = view.getMeasuredHeight();
    int duration = (int) (height/view.getContext().getResources().getDisplayMetrics().density);

    Animation animation = new Animation() {
        @Override protected void applyTransformation(float interpolatedTime, Transformation t) {
            if (expand) {
                view.getLayoutParams().height = 1;
                view.setVisibility(View.VISIBLE);
                if (interpolatedTime == 1) {
                    view.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
                } else {
                    view.getLayoutParams().height = (int) (height * interpolatedTime);
                }
                view.requestLayout();
            } else {
                if (interpolatedTime == 1) {
                    view.setVisibility(View.GONE);
                } else {
                    view.getLayoutParams().height = height - (int) (height * interpolatedTime);
                    view.requestLayout();
                }
            }
        }
        @Override public boolean willChangeBounds() {
            return true;
        }
    };

    animation.setInterpolator(easeInOutQuart);
    animation.setDuration(duration);
    view.startAnimation(animation);

}

मैंने इस कोड की कोशिश की लेकिन इसके लिए कई दृश्यों पर काम करना है, आपको स्क्रॉल करना होगा। कुछ अनुमान है इसे कैसे ठीक किया जा सकता है? stackoverflow.com/q/43916369/1009507
sammyukavi

@ यूकावी मैं इसे कई दृश्यों के साथ उपयोग कर रहा हूं और यह स्क्रॉल व्यू के अंदर ठीक काम करता है।
mjp66

एक पुनर्नवीनीकरण में क्या है?
संयुमकावि

@ युकेवी को अभी तक इसे रिसाइकलव्यू में इस्तेमाल करने की जरूरत नहीं है, लेकिन मैं यह नहीं देख सकता कि यह काम क्यों नहीं करेगा। आपको स्वयं इसके साथ थोड़ा प्रयोग करना होगा;)
mjp66

6

मैं ऊपर दिए गए बहुत ही उपयोगी उत्तर में कुछ जोड़ना चाहूंगा । यदि आपको अपने विचारों के बाद से ऊँचाई का पता नहीं है, तो .Hight () रिटर्न 0 प्राप्त करने के लिए आप निम्न कर सकते हैं:

contentView.measure(DUMMY_HIGH_DIMENSION, DUMMY_HIGH_DIMENSION);
int finalHeight = view.getMeasuredHeight();

जहां DUMMY_HIGH_DIMENSIONS की चौड़ाई / ऊंचाई (पिक्सेल में) है, आपका दृश्य इसके लिए विवश है ... जब स्क्रॉल स्क्रॉल के साथ दृश्य को एनक्रिप्टेड किया जाता है, तो यह एक बड़ी संख्या उचित है।


6

यह एक स्निपेट है जिसका उपयोग मैंने एनीमेशन के साथ एक दृश्य (रेखीय लयआउट) की चौड़ाई का आकार बदलने के लिए किया था।

कोड को लक्ष्य आकार के अनुसार विस्तार या सिकुड़ना माना जाता है। यदि आप एक भराव की चौड़ाई चाहते हैं, तो आपको ध्वज को सही पर सेट करते समय लक्ष्य चौड़ाई के रूप में मूल .getMeasuredWidth पास करना होगा।

आशा है कि यह आप में से कुछ में मदद करता है।

public class WidthResizeAnimation extends Animation {
int targetWidth;
int originaltWidth;
View view;
boolean expand;
int newWidth = 0;
boolean fillParent;

public WidthResizeAnimation(View view, int targetWidth, boolean fillParent) {
    this.view = view;
    this.originaltWidth = this.view.getMeasuredWidth();
    this.targetWidth = targetWidth;
    newWidth = originaltWidth;
    if (originaltWidth > targetWidth) {
        expand = false;
    } else {
        expand = true;
    }
    this.fillParent = fillParent;
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
    if (expand && newWidth < targetWidth) {
        newWidth = (int) (newWidth + (targetWidth - newWidth) * interpolatedTime);
    }

    if (!expand && newWidth > targetWidth) {
        newWidth = (int) (newWidth - (newWidth - targetWidth) * interpolatedTime);
    }
    if (fillParent && interpolatedTime == 1.0) {
        view.getLayoutParams().width = -1;

    } else {
        view.getLayoutParams().width = newWidth;
    }
    view.requestLayout();
}

@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
    super.initialize(width, height, parentWidth, parentHeight);
}

@Override
public boolean willChangeBounds() {
    return true;
}

}


यह काम करने के लिए कोई चाल है? कक्षा को सही मूल और लक्ष्य चौड़ाई मिलती है, लेकिन मेरे विचार आकार नहीं बदलेंगे। मैं उपयोग कर रहा हूं resizeAnim.start()। इसके साथ और बिना कोशिश किएsetFillAfter(true)
बेन केन

समझ गया। .startAnimation(resizeAnim)देखने पर फोन करना था ।
बेन केन

6

चिकनी एनीमेशन के लिए कृपया रन विधि के साथ हैंडलर का उपयोग करें ..... और आनंद लें / विस्तार करें एनीमेशन संक्षिप्त करें

    class AnimUtils{

                 public void expand(final View v) {
                  int ANIMATION_DURATION=500;//in milisecond
        v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        final int targtetHeight = v.getMeasuredHeight();

        v.getLayoutParams().height = 0;
        v.setVisibility(View.VISIBLE);
        Animation a = new Animation()
        {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                v.getLayoutParams().height = interpolatedTime == 1
                        ? LayoutParams.WRAP_CONTENT
                        : (int)(targtetHeight * interpolatedTime);
                v.requestLayout();
            }

            @Override
            public boolean willChangeBounds() {
                return true;
            }
        };

        // 1dp/ms
        a.setDuration(ANIMATION_DURATION);

      // a.setDuration((int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density));
        v.startAnimation(a);
    }



    public void collapse(final View v) {
        final int initialHeight = v.getMeasuredHeight();

        Animation a = new Animation()
        {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                if(interpolatedTime == 1){
                    v.setVisibility(View.GONE);
                }else{
                    v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
                    v.requestLayout();
                }
            }

            @Override
            public boolean willChangeBounds() {
                return true;
            }
        };

        // 1dp/ms
        a.setDuration(ANIMATION_DURATION);
       // a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
        v.startAnimation(a);
    }
}

और इस कोड का उपयोग करके कॉल करें:

       private void setAnimationOnView(final View inactive ) {
    //I am applying expand and collapse on this TextView ...You can use your view 

    //for expand animation
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {

            new AnimationUtililty().expand(inactive);

        }
    }, 1000);


    //For collapse
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {

            new AnimationUtililty().collapse(inactive);
            //inactive.setVisibility(View.GONE);

        }
    }, 8000);

}

अन्य समाधान है:

               public void expandOrCollapse(final View v,String exp_or_colpse) {
    TranslateAnimation anim = null;
    if(exp_or_colpse.equals("expand"))
    {
        anim = new TranslateAnimation(0.0f, 0.0f, -v.getHeight(), 0.0f);
        v.setVisibility(View.VISIBLE);  
    }
    else{
        anim = new TranslateAnimation(0.0f, 0.0f, 0.0f, -v.getHeight());
        AnimationListener collapselistener= new AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
            v.setVisibility(View.GONE);
            }
        };

        anim.setAnimationListener(collapselistener);
    }

     // To Collapse
        //

    anim.setDuration(300);
    anim.setInterpolator(new AccelerateInterpolator(0.5f));
    v.startAnimation(anim);
}

5

@ टोम एस्ट्रेस और @ गेराल्डो नेटो से संयुक्त समाधान

public static void expandOrCollapseView(View v,boolean expand){

    if(expand){
        v.measure(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
        final int targetHeight = v.getMeasuredHeight();
        v.getLayoutParams().height = 0;
        v.setVisibility(View.VISIBLE);
        ValueAnimator valueAnimator = ValueAnimator.ofInt(targetHeight);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                v.getLayoutParams().height = (int) animation.getAnimatedValue();
                v.requestLayout();
            }
        });
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.setDuration(500);
        valueAnimator.start();
    }
    else
    {
        final int initialHeight = v.getMeasuredHeight();
        ValueAnimator valueAnimator = ValueAnimator.ofInt(initialHeight,0);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                v.getLayoutParams().height = (int) animation.getAnimatedValue();
                v.requestLayout();
                if((int)animation.getAnimatedValue() == 0)
                    v.setVisibility(View.GONE);
            }
        });
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.setDuration(500);
        valueAnimator.start();
    }
}

//sample usage
expandOrCollapseView((Your ViewGroup),(Your ViewGroup).getVisibility()!=View.VISIBLE);

4

हां, मैं उपरोक्त टिप्पणियों से सहमत हूं। और वास्तव में, यह सही (या कम से कम सबसे आसान) की तरह प्रतीत होता है? (एक्सएमएल में) "0px" की प्रारंभिक लेआउट ऊंचाई निर्दिष्ट करने के लिए क्या करना है - और फिर आप "टॉइट" के लिए एक और तर्क में पारित कर सकते हैं ( यानी "अंतिम ऊंचाई") आपके कस्टम एनीमेशन उप-वर्ग के निर्माता के लिए, उदाहरण के लिए ऊपर के उदाहरण में, यह कुछ इस तरह दिखेगा:

    public DropDownAnim( View v, int toHeight ) { ... }

वैसे भी, उम्मीद है कि मदद करता है! :)


4

यहाँ मेरा समाधान है। मुझे लगता है कि यह सरल है। यह केवल दृश्य का विस्तार करता है, लेकिन आसानी से बढ़ाया जा सकता है।

public class WidthExpandAnimation extends Animation
{
    int _targetWidth;
    View _view;

    public WidthExpandAnimation(View view)
    {
        _view = view;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t)
    {
        if (interpolatedTime < 1.f)
        {
            int newWidth = (int) (_targetWidth * interpolatedTime);

            _view.layout(_view.getLeft(), _view.getTop(),
                    _view.getLeft() + newWidth, _view.getBottom());
        }
        else
            _view.requestLayout();
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight)
    {
        super.initialize(width, height, parentWidth, parentHeight);

        _targetWidth = width;
    }

    @Override
    public boolean willChangeBounds() {
        return true;
    }
}

4

मुझे लगता है कि सबसे आसान समाधान android:animateLayoutChanges="true"आपके लिए सेट है LinearLayoutऔर फिर इसकी दृश्यता सेट करके केवल दृश्य दिखाएं / छिपाएं। एक आकर्षण की तरह काम करता है, लेकिन आपके पास एनीमेशन अवधि पर कोई नियंत्रक नहीं है


3

आप सही रास्ते पर हैं। सुनिश्चित करें कि एनीमेशन शुरू होने से पहले आपके पास v1 सेट है शून्य लेआउट की सही ऊंचाई। आप एनीमेशन शुरू करने से पहले एनीमेशन के पहले फ्रेम की तरह दिखने के लिए अपने सेटअप को इनिशियलाइज़ करना चाहते हैं।


अगर मैं ऐसा करता हूं तो मैं सहमत हूं कि मुझे शुरुआती (मेरे एनीमेशन द्वारा आवश्यक) कैसे प्राप्त किया जाए?
टॉम एस्टेरेज़

क्या आपने वास्तव में प्रारंभिक ऊंचाई को प्रारंभिक रूप से सहेजने की कोशिश की है, वहां दृश्य दिखाई दे रहा है, और फिर v.getLayoutParams ()। ऊँचाई = 0 सेट करना; सीधे बाद में, सब इनिशियलाइज़ में?
मीका हैनलाइन

हां, अगर मैं ऐसा करता हूं तो इनिशियलाइज़ मेथड को ऊँचाई = 0
टॉम एस्टेरेज़

3

यह मेरा समाधान था, मेरी ImageViewबढ़ती 100%है 200%और res/anim/फ़ोल्डर के अंदर दो एनीमेशन फ़ाइलों का उपयोग करके अपने मूल आकार में लौटता है

anim_grow.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:interpolator="@android:anim/accelerate_interpolator">
 <scale
  android:fromXScale="1.0"
  android:toXScale="2.0"
  android:fromYScale="1.0"
  android:toYScale="2.0"
  android:duration="3000"
  android:pivotX="50%"
  android:pivotY="50%"
  android:startOffset="2000" />
</set>

anim_shrink.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:interpolator="@android:anim/accelerate_interpolator">
 <scale
  android:fromXScale="2.0"
  android:toXScale="1.0"
  android:fromYScale="2.0"
  android:toYScale="1.0"
  android:duration="3000"
  android:pivotX="50%"
  android:pivotY="50%"
  android:startOffset="2000" />
</set>

ImageViewमेरे तरीके के लिए एक भेजेंsetAnimationGrowShrink()

ImageView img1 = (ImageView)findViewById(R.id.image1);
setAnimationGrowShrink(img1);

setAnimationGrowShrink() तरीका:

private void setAnimationGrowShrink(final ImageView imgV){
    final Animation animationEnlarge = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_grow);
    final Animation animationShrink = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_shrink);

    imgV.startAnimation(animationEnlarge);

    animationEnlarge.setAnimationListener(new AnimationListener() {         
        @Override
        public void onAnimationStart(Animation animation) {}

        @Override
        public void onAnimationRepeat(Animation animation) {}

        @Override
        public void onAnimationEnd(Animation animation) {
            imgV.startAnimation(animationShrink);
        }
    });

    animationShrink.setAnimationListener(new AnimationListener() {          
        @Override
        public void onAnimationStart(Animation animation) {}

        @Override
        public void onAnimationRepeat(Animation animation) {}

        @Override
        public void onAnimationEnd(Animation animation) {
            imgV.startAnimation(animationEnlarge);
        }
    });

}

3

यह एक उचित कार्य समाधान है, मैंने इसका परीक्षण किया है:

Exapnd:

private void expand(View v) {
    v.setVisibility(View.VISIBLE);

    v.measure(View.MeasureSpec.makeMeasureSpec(PARENT_VIEW.getWidth(), View.MeasureSpec.EXACTLY),
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

    final int targetHeight = v.getMeasuredHeight();

    mAnimator = slideAnimator(0, targetHeight);
    mAnimator.setDuration(800);
    mAnimator.start();
}

ढहने:

private void collapse(View v) {
    int finalHeight = v.getHeight();

    mAnimator = slideAnimator(finalHeight, 0);

    mAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {

        }

        @Override
        public void onAnimationEnd(Animator animator) {
            //Height=0, but it set visibility to GONE
            llDescp.setVisibility(View.GONE);
        }

        @Override
        public void onAnimationCancel(Animator animator) {

        }

        @Override
        public void onAnimationRepeat(Animator animator) {

        }
    });
    mAnimator.start();
}

मूल्य एनीमेटर:

private ValueAnimator slideAnimator(int start, int end) {
    ValueAnimator mAnimator = ValueAnimator.ofInt(start, end);

    mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {
            //Update Height
            int value = (Integer) valueAnimator.getAnimatedValue();
            ViewGroup.LayoutParams layoutParams = llDescp.getLayoutParams();
            layoutParams.height = value;
            v.setLayoutParams(layoutParams);
        }
    });
    return mAnimator;
}

व्यू v एनिमेटेड होने का दृश्य है, PARENT_VIEW कंटेनर दृश्य है जिसमें दृश्य है।


2

यह droidQuery के साथ वास्तव में सरल है । प्रारंभ के लिए, इस लेआउट पर विचार करें:

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/v1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:text="View 1" />
    </LinearLayout>
    <LinearLayout
        android:id="@+id/v2"
        android:layout_width="wrap_content"
        android:layout_height="0dp" >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:text="View 2" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:text="View 3" />
    </LinearLayout>
</LinearLayout>

हम वांछित मान के लिए ऊँचाई को चेतन कर सकते हैं - कह सकते हैं 100dp- निम्नलिखित कोड का उपयोग कर:

//convert 100dp to pixel value
int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());

फिर droidQueryचेतन को उपयोग । इसका सबसे सरल तरीका है:

$.animate("{ height: " + height + "}", new AnimationOptions());

एनीमेशन को अधिक आकर्षक बनाने के लिए, एक सहजता जोड़ने पर विचार करें:

$.animate("{ height: " + height + "}", new AnimationOptions().easing($.Easing.BOUNCE));

आप विधि AnimationOptionsका उपयोग करने पर अवधि भी बदल सकते हैं duration(), या एनीमेशन समाप्त होने पर क्या हो सकता है। एक जटिल उदाहरण के लिए, प्रयास करें:

$.animate("{ height: " + height + "}", new AnimationOptions().easing($.Easing.BOUNCE)
                                                             .duration(1000)
                                                             .complete(new Function() {
                                                                 @Override
                                                                 public void invoke($ d, Object... args) {
                                                                     $.toast(context, "finished", Toast.LENGTH_SHORT);
                                                                 }
                                                             }));

2

विस्तार / पतन दृश्य के लिए सबसे अच्छा समाधान:

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        View view = buttonView.getId() == R.id.tb_search ? fSearch : layoutSettings;
        transform(view, 200, isChecked
            ? ViewGroup.LayoutParams.WRAP_CONTENT
            : 0);
    }

    public static void transform(final View v, int duration, int targetHeight) {
        int prevHeight  = v.getHeight();
        v.setVisibility(View.VISIBLE);
        ValueAnimator animator;
        if (targetHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
            v.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            animator = ValueAnimator.ofInt(prevHeight, v.getMeasuredHeight());
        } else {
            animator = ValueAnimator.ofInt(prevHeight, targetHeight);
        }
        animator.addUpdateListener(animation -> {
            v.getLayoutParams().height = (animation.getAnimatedFraction() == 1.0f)
                    ? targetHeight
                    : (int) animation.getAnimatedValue();
            v.requestLayout();
        });
        animator.setInterpolator(new LinearInterpolator());
        animator.setDuration(duration);
        animator.start();
    }

हालांकि यह काम करता है, यह डेवलपर सेटिंग्स (एनीमेशन अवधि) पर भी निर्भर करता है। और अपना कोड पॉलिश करें, लैम्ब्डा-फंक्शन और रिफॉर्मैट हटाएं onCheckedChanged
कूलमैन्ड

V के लेआउटप्रेम को बदलने के बाद केवल वी पर अनुरोध कॉल करना पर्याप्त क्यों है? मैंने सोचा था कि यह अनुरोध करने के लिए आवश्यक होगा वी के माता
vlazzle

2

आप एक मामूली मोड़ के साथ एक ViewPropertyAnimator का उपयोग कर सकते हैं। ढहने के लिए, दृश्य को 1 पिक्सेल की ऊंचाई पर स्केल करें, फिर इसे छिपाएं। विस्तार करने के लिए, इसे दिखाएं, फिर इसे इसकी ऊंचाई तक विस्तारित करें।

private void collapse(final View view) {
    view.setPivotY(0);
    view.animate().scaleY(1/view.getHeight()).setDuration(1000).withEndAction(new Runnable() {
        @Override public void run() {
            view.setVisibility(GONE);
        }
    });
}

private void expand(View view, int height) {
    float scaleFactor = height / view.getHeight();

    view.setVisibility(VISIBLE);
    view.setPivotY(0);
    view.animate().scaleY(scaleFactor).setDuration(1000);
}

धुरी दृश्य को बताती है कि किस पैमाने से, डिफ़ॉल्ट मध्य में है। अवधि वैकल्पिक है (डिफ़ॉल्ट = 1000)। आप उपयोग करने के लिए इंटरपोलर भी सेट कर सकते हैं, जैसे.setInterpolator(new AccelerateDecelerateInterpolator())


1

मैंने संस्करण बनाया है जिसमें आपको लेआउट की ऊँचाई निर्दिष्ट करने की आवश्यकता नहीं है, इसलिए यह उपयोग करने के लिए बहुत आसान और क्लीनर है। समाधान एनीमेशन के पहले फ्रेम में ऊंचाई प्राप्त करना है (यह उस समय उपलब्ध है, कम से कम मेरे परीक्षणों के दौरान)। इस तरह आप एक मनमाना ऊंचाई और नीचे मार्जिन के साथ एक दृश्य प्रदान कर सकते हैं।

कंस्ट्रक्टर में एक छोटी सी हैक भी होती है - निचला मार्जिन -10000 पर सेट होता है, ताकि व्यू ट्रांसफॉर्मेशन से पहले छिपा रहे (फ़्लिकर को रोकता है)।

public class ExpandAnimation extends Animation {


    private View mAnimatedView;
    private ViewGroup.MarginLayoutParams mViewLayoutParams;
    private int mMarginStart, mMarginEnd;

    public ExpandAnimation(View view) {
        mAnimatedView = view;
        mViewLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
        mMarginEnd = mViewLayoutParams.bottomMargin;
        mMarginStart = -10000; //hide before viewing by settings very high negative bottom margin (hack, but works nicely)
        mViewLayoutParams.bottomMargin = mMarginStart;
        mAnimatedView.setLayoutParams(mViewLayoutParams);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
            //view height is already known when the animation starts
            if(interpolatedTime==0){
                mMarginStart = -mAnimatedView.getHeight();
            }
            mViewLayoutParams.bottomMargin = (int)((mMarginEnd-mMarginStart) * interpolatedTime)+mMarginStart;
            mAnimatedView.setLayoutParams(mViewLayoutParams);
    }
}

1

मान उपयोग करें:

ValueAnimator expandAnimation = ValueAnimator.ofInt(mainView.getHeight(), 400);
expandAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(final ValueAnimator animation) {
        int height = (Integer) animation.getAnimatedValue();
        RelativeLayout.LayoutParams lp = (LayoutParams) mainView.getLayoutParams();
        lp.height = height;
    }
});


expandAnimation.setDuration(500);
expandAnimation.start();

मेरे मामले में कुछ भी नहीं करता है। इसके अलावा, आप अपने कोड को कम कर सकते हैं, 2 लाइनों को ढहा सकते हैं mainView.getLayoutParams().height = height
कूलमाइंड

1
public static void slide(View v, int speed, int pos) {
    v.animate().setDuration(speed);
    v.animate().translationY(pos);
    v.animate().start();
}

// slide down
slide(yourView, 250, yourViewHeight);
// slide up
slide(yourView, 250, 0);

1
/**
 * Animation that either expands or collapses a view by sliding it down to make
 * it visible. Or by sliding it up so it will hide. It will look like it slides
 * behind the view above.
 * 
 */
public class FinalExpandCollapseAnimation extends Animation
{
    private View mAnimatedView;
    private int mEndHeight;
    private int mType;
    public final static int COLLAPSE = 1;
    public final static int EXPAND = 0;
    private LinearLayout.LayoutParams mLayoutParams;
    private RelativeLayout.LayoutParams mLayoutParamsRel;
    private String layout;
    private Context context;

    /**
     * Initializes expand collapse animation, has two types, collapse (1) and
     * expand (0).
     * 
     * @param view
     *            The view to animate
     * @param type
     *            The type of animation: 0 will expand from gone and 0 size to
     *            visible and layout size defined in xml. 1 will collapse view
     *            and set to gone
     */
    public FinalExpandCollapseAnimation(View view, int type, int height, String layout, Context context)
    {
        this.layout = layout;
        this.context = context;
        mAnimatedView = view;
        mEndHeight = mAnimatedView.getMeasuredHeight();
        if (layout.equalsIgnoreCase("linear"))
            mLayoutParams = ((LinearLayout.LayoutParams) view.getLayoutParams());
        else
            mLayoutParamsRel = ((RelativeLayout.LayoutParams) view.getLayoutParams());
        mType = type;
        if (mType == EXPAND)
        {
            AppConstant.ANIMATED_VIEW_HEIGHT = height;
        }
        else
        {
            if (layout.equalsIgnoreCase("linear"))
                mLayoutParams.topMargin = 0;
            else
                mLayoutParamsRel.topMargin = convertPixelsIntoDensityPixels(36);
        }
        setDuration(600);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t)
    {
        super.applyTransformation(interpolatedTime, t);
        if (interpolatedTime < 1.0f)
        {
            if (mType == EXPAND)
            {
                if (layout.equalsIgnoreCase("linear"))
                {
                    mLayoutParams.height = AppConstant.ANIMATED_VIEW_HEIGHT
                            + (-AppConstant.ANIMATED_VIEW_HEIGHT + (int) (AppConstant.ANIMATED_VIEW_HEIGHT * interpolatedTime));
                }
                else
                {
                    mLayoutParamsRel.height = AppConstant.ANIMATED_VIEW_HEIGHT
                            + (-AppConstant.ANIMATED_VIEW_HEIGHT + (int) (AppConstant.ANIMATED_VIEW_HEIGHT * interpolatedTime));
                }
                mAnimatedView.setVisibility(View.VISIBLE);
            }
            else
            {
                if (layout.equalsIgnoreCase("linear"))
                    mLayoutParams.height = mEndHeight - (int) (mEndHeight * interpolatedTime);
                else
                    mLayoutParamsRel.height = mEndHeight - (int) (mEndHeight * interpolatedTime);
            }
            mAnimatedView.requestLayout();
        }
        else
        {
            if (mType == EXPAND)
            {
                if (layout.equalsIgnoreCase("linear"))
                {
                    mLayoutParams.height = AppConstant.ANIMATED_VIEW_HEIGHT;
                    mLayoutParams.topMargin = 0;
                }
                else
                {
                    mLayoutParamsRel.height = AppConstant.ANIMATED_VIEW_HEIGHT;
                    mLayoutParamsRel.topMargin = convertPixelsIntoDensityPixels(36);
                }
                mAnimatedView.setVisibility(View.VISIBLE);
                mAnimatedView.requestLayout();
            }
            else
            {
                if (layout.equalsIgnoreCase("linear"))
                    mLayoutParams.height = 0;
                else
                    mLayoutParamsRel.height = 0;
                mAnimatedView.setVisibility(View.GONE);
                mAnimatedView.requestLayout();
            }
        }
    }

    private int convertPixelsIntoDensityPixels(int pixels)
    {
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        return (int) metrics.density * pixels;
    }
}

वर्ग को निम्नलिखित तरीके से बुलाया जा सकता है

   if (findViewById(R.id.ll_specailoffer_show_hide).getVisibility() == View.VISIBLE) {
                        ((ImageView) findViewById(R.id.iv_specialhour_seemore)).setImageResource(R.drawable.white_dropdown_up);

                        FinalExpandCollapseAnimation finalExpandCollapseAnimation = new FinalExpandCollapseAnimation(
                                findViewById(R.id.ll_specailoffer_show_hide),
                                FinalExpandCollapseAnimation.COLLAPSE,
                                SpecialOfferHeight, "linear", this);
                        findViewById(R.id.ll_specailoffer_show_hide)
                                .startAnimation(finalExpandCollapseAnimation);
                        ((View) findViewById(R.id.ll_specailoffer_show_hide).getParent()).invalidate();
                    } else {
                        ((ImageView) findViewById(R.id.iv_specialhour_seemore)).setImageResource(R.drawable.white_dropdown);

                        FinalExpandCollapseAnimation finalExpandCollapseAnimation = new FinalExpandCollapseAnimation(
                                findViewById(R.id.ll_specailoffer_show_hide),
                                FinalExpandCollapseAnimation.EXPAND,
                                SpecialOfferHeight, "linear", this);
                        findViewById(R.id.ll_specailoffer_show_hide)
                                .startAnimation(finalExpandCollapseAnimation);
                        ((View) findViewById(R.id.ll_specailoffer_show_hide).getParent()).invalidate();
                    }

1

@Tom Esterez और @ सेठ नेल्सन (शीर्ष 2) के समाधानों के आधार पर मैंने उनका अनुकरण किया। साथ ही मूल समाधान यह डेवलपर विकल्पों (एनीमेशन सेटिंग्स) पर निर्भर नहीं करता है।

private void resizeWithAnimation(final View view, int duration, final int targetHeight) {
    final int initialHeight = view.getMeasuredHeight();
    final int distance = targetHeight - initialHeight;

    view.setVisibility(View.VISIBLE);

    Animation a = new Animation() {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            if (interpolatedTime == 1 && targetHeight == 0) {
                view.setVisibility(View.GONE);
            }
            view.getLayoutParams().height = (int) (initialHeight + distance * interpolatedTime);
            view.requestLayout();
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };

    a.setDuration(duration);
    view.startAnimation(a);
}

खैर, 3 साल बाद मैंने फिर से कई समाधानों का परीक्षण किया, लेकिन केवल मेरा काम सही था।
कूलमैन्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.