Android: Animasyonu genişlet / daralt


449

Diyelim ki dikey bir doğrusal düzenim var:

[v1]
[v2]

Varsayılan olarak v1 görünür şekilde = GONE değerine sahiptir. V1'i bir genişleme animasyonu ile göstermek ve v2'yi aynı anda aşağı itmek istiyorum.

Ben böyle bir şey denedim:

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;
    }
};

Ancak bu çözümle, animasyon başladığında göz kırpıyorum. Animasyon uygulanmadan önce v1'in tam boyutta görüntülenmesinden kaynaklandığını düşünüyorum.

Javascript ile, bu jQuery bir satırdır! Bunu android ile yapmanın basit bir yolu var mı?

Yanıtlar:


734

Bu sorunun popüler hale geldiğini görüyorum, bu yüzden gerçek çözümümü gönderiyorum. Ana avantajı, animasyonu uygulamak için genişletilmiş yüksekliği bilmeniz gerekmemesi ve görünüm genişletildikten sonra, içerik değişirse yüksekliği uyarlar. Benim için harika çalışıyor.

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);
}

@Jefferson tarafından yorumlarda belirtildiği gibi, animasyonun süresini (ve dolayısıyla hızını) değiştirerek daha akıcı bir animasyon elde edebilirsiniz. Şu anda 1dp / ms hızında ayarlanmıştır


13
v.measure (MeasureSpec.makeMeasureSpec (LayoutParams.MATCH_PARENT, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec (LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY)); Bazı durumlarda (my - ListView) bu uyumsuzluk yanlış targtetHeight değerine yol açar
Johnny Doe

12
@Tom Esterez Bu işe yarıyor, ama çok düzgün değil. Sorunsuz bir şekilde yapmak için başka işler var mı?
acntwww

9
@acntwww Süreyi 4 gibi bir faktörle çarparak sorunsuz bir animasyon elde edebilirsiniz.a.setDuration(((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density)) * 4)
Jefferson Henrique C. Soares

10
@Alioo, ithalat android.view.animation.Transformation;
Jomia

5
Harika çalışıyor! Sabit bir dp elemanını genişletmek istediğim için ölçülen yükseklikle ilgili problemlerim vardı, bu yüzden ölçüyü değiştirdim v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));ve v.getLayoutParams().height = interpolatedTime == 1 ? targetHeight : (int)(targetHeight * interpolatedTime);Bu benim için çalıştı!
vkislicins

140

Çok benzer bir animasyon olduğuna inandığım şeyi yapmaya çalışıyordum ve zarif bir çözüm buldum. Bu kod her zaman 0-> h veya h-> 0 (h maksimum yüksekliktir) olduğunu varsaymaktadır. Üç kurucu parametresi view = canlandırılacak görünüm (benim durumumda bir web görünümü), targetHeight = görünümün maksimum yüksekliği ve down = yönü belirten bir boolean (true = genişleyen, false = daraltma) şeklindedir.

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
Kodda bir yazım hatası vardır: "initalize" yöntem adı "başlat" olmalıdır veya çağrılmaz. ;) Gelecekte @Override kullanmanızı tavsiye ederim, böylece bu tür yazım hataları derleyici tarafından yakalanır.
Lorne Laliberte

4
Aşağıdakileri yapıyorum: "DropDownAnim anim = new DropDownAnim (grid_titulos_atual, GRID_HEIGHT, true); anim.setDuration (500); anim.start ();" ama işe yaramıyor. ApplyTransformation üzerinde bazı kesme noktaları yerleştirdim ancak bunlara asla ulaşılamıyor
Paulo Cesar

5
Ops, işe yaradı, view.startAnimation (a) ... Performans çok iyi değil, ama çalışıyor :)
Paulo Cesar

3
@IamStalker Bu durumda, büyük olasılıkla iki yükseklik ile başlamalısınız: StartHeight ve endingHeight. Sonra şu şekilde değiştirin: if (down) {newHeight = (int) (((endingHeight-startupHeight) * interpolatedTime) + startupHeight); } else {newHeight = (int) (((endingHeight-startupHeight) * (1 - interpolatedTime)) + startupHeight); }
Seth Nelson

3
@Seth Bence newHeight basitçe (int) (((targetHeight -startingHeight) * interpolatedTime) + startupHeight), startHeight initialize () olarak ayarlandığı sürece yön olsun.
Giorgos Kylafas

138

Bugün aynı sorunun üstesinden geldim ve sanırım bu sorunun asıl çözümü bu

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

Bu özelliği, vardiyada yer alan en üstteki tüm düzenler için ayarlamanız gerekir. Şimdi bir mizanpajın görünürlüğünü GONE olarak ayarlarsanız, diğeri kaybolan mizanpajı serbest bıraktığı için alan kaplar. Bir çeşit "solma" olan varsayılan bir animasyon olacak, ancak bunu değiştirebileceğinizi düşünüyorum - ama şimdilik test etmediğim son film.


2
+1, Şimdi Hız arıyorum: animateLayoutChanges süresi
Tushar Pandey


Geri düğmesine bastıktan sonra çalışmaz. Herhangi bir öneri?
Hassan Tareq

4
Bu, genişleme animasyonu için mükemmel çalışır, ancak daralma için animasyon, üst düzen küçüldükten sonra gerçekleşir.
shine_joseph

3
@shine_joseph evet bunu bir geri dönüşüm görünümünde kullanıyorum ve çöken zaman gerçekten garip görünüyor: /
AmirG

65

Bana düzgün çalışmayan @LenaYan'ın çözümünü aldım ( çünkü Görünümü daraltmadan ve / veya genişletmeden önce 0 yükseklik görünümüne dönüştürüyordu ) ve bazı değişiklikler yaptım.

Şimdi , Görünüm'ün önceki yüksekliğini alarak ve bu boyutla genişlemeye başlayarak harika çalışıyor . Çöken aynı şeydir.

Aşağıdaki kodu kopyalayıp yapıştırabilirsiniz:

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();
}

Kullanımı:

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

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

Yeterince kolay!

İlk kod için LenaYan'a teşekkürler!


Çalışmasına rağmen geliştirici ayarlarına (animasyon süresi) bağlıdır. Devre dışı bırakılırsa, animasyon gösterilmez.
CoolMind

Evet, ancak bir sorun olabilir veya olmayabilir. Uygulamanıza bağlıdır. Örneğin, animasyon süresini basit değişikliklerle genişletilmiş / daraltılmış boyutla kolayca orantılı hale getirebilirsiniz. Ayarlanabilir bir animasyon süresine sahip olmak size biraz daha fazla özgürlük verir.
Geraldo Neto

Animasyon çalışmıyor'u genişletin. animasyonu daraltmaya benziyor.
Ahamadullah Saikat

39

Alternatif olarak, genişletmek için aşağıdaki ölçeklendirme faktörlerine sahip bir ölçek animasyonu kullanmaktır:

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

ve çökmek için:

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

animasyon nasıl başlatılır .. View.startAnimation (anim); işe yaramıyor
Mahendran

Animasyonu nasıl başlattığım tam olarak bu. Diğer animasyonlar işinize yarıyor mu?
ChristophK

1
Bu yaklaşımla gitti, bir cazibe gibi çalışıyor ve zaten uygulanmış olanları uygulamaya gerek yok.
erbsman

15
Bu, animasyon sırasında altındaki görünümleri aşağı itmez ve animasyonlu görünümü 0 -> h'den uzatıyormuş gibi görünür.

5
Btw, view animations ölçeklendirme için harika çalışıyor: oView.animate (). ScaleY (0) dikey olarak daraltmak için; oView.animate (). scaleY (1) öğesini açın (yalnızca sdk 12 ve üstü sürümlerde kullanılabilir olduğuna dikkat edin).
Kirk B.15

27

@Tom Esterez'in cevabı , ancak Android başına view.measure () kullanacak şekilde güncellendi getMeasuredHeight yanlış değerler döndürüyor!

    // 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 ve DURATION_MULTIPLIER nedir?
MidasLefko

Bunları unuttum, addHeight, genişlemenizde (muhtemelen değil) ekstra yüksekliğe ihtiyacınız olduğunda ve DURATION_MODIFIER, animasyonları hızlandırmak / yavaşlatmak istediğinizde sadece bir hız değiştiricidir.
Erik B

1
Harika çalışıyor! Son satırda yalnızca bir sözcükle TextView kullanılırken küçük bir gecikme oluşur. PathInterpolator'ın ne yaptığını açıklayabilir misiniz?
yennsarah

EaseInOutQuart çok doğal bir his için animasyonu önce yavaş, sonra hızlı, sonra yavaş yapar. Burada derinlemesine konuşuyorlar easings.net
Erik B

1
yöntemini denedim ama animasyon sona erdiğinde benim görüş artık görünmez.
Aman Verma

26

Tamam, ben ÇOK çirkin bir çözüm buldum:

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;
}

Daha iyi bir çözüm önermekten çekinmeyin!


3
+1, bu çirkin olarak adlandırılsa bile, henüz boyutunu bilmediğimiz bir görünüm için çalışır (örneğin, ebeveyne yeni oluşturulmuş bir görünüm (boyutu FILL_PARENT olan) eklersek ve canlandırmak isteriz bu süreç, ebeveyn boyutu büyümesini canlandırma dahil).
Vit Khudenko

BTW, View.onMeause(widthMeasureSpec, heightMeasureSpec)çağrıda küçük bir hata var gibi görünüyor , bu nedenle genişlik ve yükseklik özellikleri değiştirilmelidir.
Vit Khudenko

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
Bu sorun var ... daraltılabilir görünümdeki içerik genişletme sırasında kayboluyor. Bu görünümü genişletirken kaybolan Recycler View'um var. LenaYan
Akshay Mahajan

21

Tamamen genişletmek veya daraltmak istemiyorsanız - işte basit bir HeightAnimation -

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;
    }
}

Kullanımı:

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

13

Ben uyarlanan Tom Esterez tarafından şu anda kabul cevabı çalıştı ama dalgalı vardı ve çok animasyon düzgün değil. Benim çözümüm temelde yerini Animationbir ile ValueAnimatorbir takılabilir, hangiInterpolator vb aşma, sıçrama, hızlandırmak, gibi çeşitli efektler elde Seçtiğiniz

Bu çözüm WRAP_CONTENT, öncelikle gerekli gerçek yüksekliği ölçtükten ve sonra bu yüksekliğe hareketlendirdiğinden, dinamik bir yüksekliğe (yani kullanarak ) sahip görünümlerle harika çalışır .

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();
}

Daha sonra sadece expand( myView ); ya dacollapse( myView ); .


Teşekkürler. Minimum yükseklik 0 olmadığında da bir durum ekleyebilirsiniz.
CoolMind

Benim için lineerlayout için çalışıyor
Roger

Sadece kullanılan paramları düzeltti v.measure()ve şimdi mükemmel çalışıyor. Teşekkürler!
Shahood ul Hassan

9

Kotlin Uzatma Fonksiyonlarını Kullanmak Test Edildi ve En Kısa Cevap

Herhangi bir Görünümde animateVisibility (genişlet / daralt) öğesini çağırmanız yeterlidir.

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()
}

Aynı cevabı göndermek istedim :) Çok kötü bu çok derin burried.
muetzenflo

@muetzenflo Cevabı giderek daha fazla kişi cevaplarsa, ortaya çıkacaktır. :)
Rajkiran

Genişletildiğinde, metin görünümü yalnızca bir satır gösterecek şekilde, wrap_content yüksekliğine sahip birden fazla satır içeren bir metin görünümü olup olmadığını anlayana kadar bu çözümü beğendim. Şimdi düzeltmeye çalışıyorum
olearyj234

Bunu denedim, ancak animasyon düzgün görünmüyor. Genişletmek için, Metin görünümünün tamamı kısa bir süre için görünür ve ardından animasyon oynatılır. Daralma için, metin görünümü, herhangi bir nedenle, daraltıldıktan hemen sonra yeniden genişler. Ne yaptığımı biliyor musun?
Anchith Acharya

7

Tom Esterez'in mükemmel cevabına ve Erik B'nin mükemmel güncellemesine ek olarak, genişleme ve sözleşme yöntemlerini bir araya getirerek kendi çekimimi göndereceğimi düşündüm. Bu şekilde, örneğin böyle bir eylemde bulunabilirsiniz ...

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

... aşağıdaki yöntemi çağıran ve her onClick () öğesinden sonra ne yapacağını anlamasına izin veren ...

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);

}

Bu kodu denedim ama bunun için birden çok görünümde yedekte çalışma, kaydırmak zorunda. Bunu nasıl düzeltebileceğim hakkında bir fikrin var mı? stackoverflow.com/q/43916369/1009507
sammyukavi

@Ukavi Bunu birden çok görünümle kullanıyorum ve bir ScrollView içinde iyi çalışıyor.
mjp66

Geri dönüşüm görünümüne ne dersiniz?
sammyukavi

@Ukavi henüz geri dönüşüm görünümünde kullanmaya ihtiyaç duymadı ancak neden işe yaramayacağını göremiyorum. Bunu kendiniz ile küçük bir deney gerekecek;)
mjp66

6

Yukarıdaki çok yardımcı cevaba bir şeyler eklemek istiyorum . Görünümleriniz .getHeight () 0 değerini döndürdüğü için sonuçlanacak yüksekliği bilmiyorsanız, yüksekliği elde etmek için aşağıdakileri yapabilirsiniz:

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

DUMMY_HIGH_DIMENSIONS, görünümünüzle sınırlandırılan genişlik / yükseklik (piksel cinsinden) olduğunda, görünüm bir ScrollView ile kapsüllendiğinde çok büyük bir sayıya sahip olmak makul olur.


6

Bu, bir görünümün genişliğini (LinearLayout) animasyonla yeniden boyutlandırmak için kullandığım bir parçacık.

Kodun hedef boyuta göre genişlemesi veya daralması gerekiyor. Fill_parent width istiyorsanız, flag değerini true olarak ayarlarken .getMeasuredWidth üst öğesini hedef genişliği olarak iletmeniz gerekir.

Umarım bazılarına yardımcı olur.

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;
}

}


Bunun işe yaraması için bir hile var mı? Sınıf doğru orijinal ve hedef genişlikleri alır, ancak görünümlerim yeniden boyutlandırılmaz. Kullanıyorum resizeAnim.start(). Ayrıca ve olmadan denedimsetFillAfter(true)
Ben Kane

Anladım. .startAnimation(resizeAnim)Görünümü çağırmak zorunda kaldı .
Ben Kane

6

Pürüzsüz animasyon için lütfen çalışma yöntemiyle Handler kullanın ..... ve Animasyonun Genişlet / Daraltının tadını çıkarın

    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);
    }
}

Ve bu kodu kullanarak arayın:

       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);

}

Diğer çözüm:

               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

@Tom Esterez ve @Geraldo Neto'dan kombine çözümler

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

Evet, yukarıdaki yorumları kabul ettim. Ve aslında, yapılacak en doğru şey (veya en azından en kolay?) Gibi gözüküyor (XML'de) "0px" başlangıç ​​düzen yüksekliğini belirtmek - ve sonra "toHeight" ( örneğin, "son yükseklik") özel Animasyon alt sınıfınızın yapıcısına, örneğin yukarıdaki örnekte, şöyle görünür:

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

Neyse, yardımcı olacağını umuyoruz! :)


4

İşte benim çözümüm. Bence daha basit. Yalnızca görünümü genişletir, ancak kolayca genişletilebilir.

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

Ben kolay çözüm kümesine olduğunu düşünüyorum android:animateLayoutChanges="true"sizin için LinearLayoutgörünürlüğünü seting tarafından ve sadece göstermek / gizlemek görünümü. Bir cazibe gibi çalışır, ancak animasyon süresini kontrol edemezsiniz


3

Doğru yoldasın. Animasyon başlamadan hemen önce v1'in mizanpaj yüksekliğini sıfır olarak ayarladığınızdan emin olun. Animasyona başlamadan önce kurulumunuzu animasyonun ilk karesine benzeyecek şekilde başlatmak istiyorsunuz.


Kabul ediyorum ama bunu yaparsam initialHeight (animasyonum için gerekli) nasıl alınır?
Tom Esterez

Başlangıçta başlangıç ​​yüksekliğini kaydetmeyi, orada görünür görünmeyi ayarlamayı ve sonra v.getLayoutParams () ayarını denediniz mi? Height = 0; doğrudan sonra, hepsi başlangıçta?
Micah Hainline

Evet, bunu yaparsam, başlatma yöntemi height = 0 ile çağrılır
Tom Esterez

3

Bu benim çözüm oldu benim ImageViewyetişen 100%kadar 200%içeride iki animasyon dosyalarını kullanarak, onun orijinal boyutuna iade veres/anim/ klasörün

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>

Bir gönder ImageViewbenim yöntemesetAnimationGrowShrink()

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

setAnimationGrowShrink() yöntem:

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

Bu uygun bir çalışma çözümü, test ettim:

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();
}

Çöküş:

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();
}

Değer Animatörü:

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;
}

Görünüm v, animasyon uygulanacak görünümdür, PARENT_VIEW görünümü içeren kapsayıcı görünümdür.


2

Bu droidQuery ile gerçekten çok basit . Başlangıçlar için şu düzeni göz önünde bulundurun:

<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>

100dpAşağıdaki kodu kullanarak yüksekliği istenen değere (örneğin,) hareketlendirebiliriz :

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

Ardından droidQueryanimasyon yapmak için kullanın . En basit yol şudur:

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

Animasyonu daha çekici hale getirmek için bir hareket hızı eklemeyi düşünün:

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

Ayrıca yöntemi AnimationOptionskullanma süresini değiştirebilir duration()veya animasyon sona erdiğinde ne olacağını işleyebilirsiniz. Karmaşık bir örnek için şunu deneyin:

$.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

Görünümü genişlet / daralt için en iyi çözüm:

    @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();
    }

Çalışmasına rağmen, geliştirici ayarlarına da bağlıdır (animasyon süresi). Ve kodunuzu parlatın, lambda işlevini silin ve yeniden biçimlendirin onCheckedChanged.
CoolMind

Neden v'nin LayoutParams'ını değiştirdikten sonra requestLayout'u yalnızca v'de çağırmak yeterli?
V'nin

2

Hafif bir bükülme ile ViewPropertyAnimator kullanabilirsiniz. Daraltmak için, görünümü 1 piksel yüksekliğe ölçeklendirin ve gizleyin. Genişletmek için gösterin, ardından yüksekliğine genişletin.

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);
}

Pivot görünüme nereden ölçekleneceğini söyler, varsayılan ortadadır. Süre isteğe bağlıdır (varsayılan = 1000). İnterpolatörü aşağıdaki gibi kullanmak üzere de ayarlayabilirsiniz.setInterpolator(new AccelerateDecelerateInterpolator())


1

Düzen yüksekliğini belirtmeniz gerekmeyen bir sürüm oluşturdum, bu nedenle kullanımı çok daha kolay ve temiz. Çözüm, animasyonun ilk karesinde yüksekliği elde etmektir (o anda, en azından testlerim sırasında kullanılabilir). Bu yolla, keyfi yükseklik ve alt kenar boşluğuna sahip bir Görünüm sağlayabilirsiniz.

Ayrıca yapıcıda küçük bir hack vardır - alt kenar boşluğu -10000 olarak ayarlanır, böylece görünüm dönüşümden önce gizli kalır (titremeyi önler).

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 kullanın:

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();

Benim durumumda hiçbir şey yapmaz. Ayrıca 2 satır daraltarak kodunuzu kolaylaştırabilirsiniz mainView.getLayoutParams().height = height.
CoolMind

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;
    }
}

Sınıf aşağıdaki şekilde çağrılabilir

   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 ve @Seth Nelson (ilk 2) 'nin çözümlerine dayanarak onları sildim. Orijinal çözümlerin yanı sıra Geliştirici seçeneklerine (animasyon ayarları) bağlı değildir.

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 yıl sonra tekrar birkaç çözümü test ettim, ama sadece benimki doğru çalıştı.
CoolMind
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.