View.setVisibility'yi (GONE) nasıl canlandırırım


84

Görünürlük ayarını Animationaldığında bir tane yapmak istiyorum . Kaybolmak yerine, "çökmesi" gerekir. Bunu bir ile denedim ama sonra daraltıldı, ancak düzen yalnızca duraklardan (veya başlamadan) sonra (veya önce) alanını yeniden boyutlandıracak .ViewGONEViewScaleAnimationViewAnimation

AnimationAnimasyon yaparken, Viewboş bir alan yerine alt s'lerin doğrudan içeriğin altında kalması için nasıl yapabilirim ?


Andy'nin burada sunduğu tekniği ExpandAnimation'da kullandım: udinic.wordpress.com/2011/09/03/expanding-listview-items Ölçekli bir animasyon kullanmadım, yeni bir Animasyon oluşturdum bunun için sınıf.
Udinic

Bunu yapmaya çalışırken bu çok faydalı oldu. Teşekkür ederim
atraudes

Mükemmel Udinic .. sorunumu gerçekten çözdü .. :) teşekkürler
Yousuf Qureshi

Harika, sorunuma uyum sağlamam gerekiyor ama sonunda işe yarıyor. Benim için bu çözüm diğer cevaptan daha iyiydi.
Derzu

Yanıtlar:


51

API aracılığıyla bunu yapmanın kolay bir yolu yok gibi görünüyor, çünkü animasyon sadece görünümün gerçek boyutunu değil, görünümün işleme matrisini değiştiriyor. Ancak LinearLayout'u görünümün küçüldüğünü düşünmeye ikna etmek için negatif bir marj belirleyebiliriz.

Bu nedenle, ScaleAnimation'a dayalı olarak kendi Animation sınıfınızı oluşturmanızı ve yeni kenar boşlukları ayarlamak ve düzeni güncellemek için "applyTransformation" yöntemini geçersiz kılmanızı öneririm. Bunun gibi...

public class Q2634073 extends Activity implements OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.q2634073);
        findViewById(R.id.item1).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        view.startAnimation(new MyScaler(1.0f, 1.0f, 1.0f, 0.0f, 500, view, true));
    }

    public class MyScaler extends ScaleAnimation {

        private View mView;

        private LayoutParams mLayoutParams;

        private int mMarginBottomFromY, mMarginBottomToY;

        private boolean mVanishAfter = false;

        public MyScaler(float fromX, float toX, float fromY, float toY, int duration, View view,
                boolean vanishAfter) {
            super(fromX, toX, fromY, toY);
            setDuration(duration);
            mView = view;
            mVanishAfter = vanishAfter;
            mLayoutParams = (LayoutParams) view.getLayoutParams();
            int height = mView.getHeight();
            mMarginBottomFromY = (int) (height * fromY) + mLayoutParams.bottomMargin - height;
            mMarginBottomToY = (int) (0 - ((height * toY) + mLayoutParams.bottomMargin)) - height;
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            if (interpolatedTime < 1.0f) {
                int newMarginBottom = mMarginBottomFromY
                        + (int) ((mMarginBottomToY - mMarginBottomFromY) * interpolatedTime);
                mLayoutParams.setMargins(mLayoutParams.leftMargin, mLayoutParams.topMargin,
                    mLayoutParams.rightMargin, newMarginBottom);
                mView.getParent().requestLayout();
            } else if (mVanishAfter) {
                mView.setVisibility(View.GONE);
            }
        }

    }

}

Genel uyarı geçerlidir: Korumalı bir yöntemi (applyTransformation) geçersiz kıldığımız için, bunun Android'in gelecekteki sürümlerinde çalışacağı garanti edilmez.


3
Neden bunu düşünmedim ?! Teşekkür ederim. Ayrıca şunu anlamıyorum: "Her zamanki uyarı geçerlidir: korumalı bir yöntemi (applyTransformation) geçersiz kıldığımız için, bunun Android'in gelecekteki sürümlerinde çalışacağı garanti edilmiyor." - Korumalı işlevler API sürümleri arasında neden farklılık gösteriyor? Bunlar gizli değildir ve onları geçersiz kılabilmeniz için korumalı olarak uygulanır (aksi takdirde paket kapsamına alınırlar).
MrSnowflake

Muhtemelen korumalı yöntem konusunda haklısınız. Bunlara bir API'de erişme konusunda aşırı temkinli olma eğilimindeyim.
Andy

1
Bu işe "çöken" almak dışında benim için çok çalıştı (fromY = 0.0f, oyuncak = 1.0f), ben kaldırmak zorunda 0 - içinde marginBottomToYhesaplama.
dmon

2
Genel türü kullanmanızı öneririm MarginLayoutParamsBelirli bir yerineLayoutParam .
Paul Lammertsma

3
Diyelim ki geçiş animasyonu yapmalıyım, sonra bunu tersine nasıl yapabilirim. Lütfen tavsiye.
Umesh

99

Görünümü bir düzene yerleştirin android:animateLayoutChanges="true"ve bu düzen için ayarlayın .


1
Minimum API gerekli 11 veya üstü! Bu yöntemi daha düşük sürüm için kullanamazsınız.
Nagaraj Alagusudaram

2
bu, en küçümsenen düzen özelliğidir ... teşekkür ederim!
Andres Santiago

7

Andy'nin burada sunduğu ile aynı tekniği kullandım. Bunun için kenar boşluğunun değerini canlandıran, öğenin etkisinin kaybolmasına / görünmesine neden olan kendi Animasyon sınıfımı yazdım. Şöyle görünüyor:

public class ExpandAnimation extends Animation {

// Initializations...

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
    super.applyTransformation(interpolatedTime, t);

    if (interpolatedTime < 1.0f) {

        // Calculating the new bottom margin, and setting it
        mViewLayoutParams.bottomMargin = mMarginStart
                + (int) ((mMarginEnd - mMarginStart) * interpolatedTime);

        // Invalidating the layout, making us seeing the changes we made
        mAnimatedView.requestLayout();
    }
}
}

Blog yazım http://udinic.wordpress.com/2011/09/03/expanding-listview-items/ üzerinde çalışan tam bir örneğim var


2

Burada Andy ile aynı tekniği kullandım ve burada açıklanan bir tekniği kullanarak, aksaklık olmadan genişletmek ve daraltmak için kullanılabilecek şekilde geliştirdim: https://stackoverflow.com/a/11426510/1317564

import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.ScaleAnimation;
import android.view.animation.Transformation;
import android.widget.LinearLayout;

class LinearLayoutVerticalScaleAnimation extends ScaleAnimation {
    private final LinearLayout view;
    private final LinearLayout.LayoutParams layoutParams;

    private final float beginY;
    private final float endY;
    private final int originalBottomMargin;

    private int expandedHeight;
    private boolean marginsInitialized = false;
    private int marginBottomBegin;
    private int marginBottomEnd;

    private ViewTreeObserver.OnPreDrawListener preDrawListener;

    LinearLayoutVerticalScaleAnimation(float beginY, float endY,
            LinearLayout linearLayout) {
        super(1f, 1f, beginY, endY);

        this.view = linearLayout;
        this.layoutParams = (LinearLayout.LayoutParams) linearLayout.getLayoutParams();

        this.beginY = beginY;
        this.endY = endY;
        this.originalBottomMargin = layoutParams.bottomMargin;

        if (view.getHeight() != 0) {
            expandedHeight = view.getHeight();
            initializeMargins();
        }
    }

    private void initializeMargins() {
        final int beginHeight = (int) (expandedHeight * beginY);
        final int endHeight = (int) (expandedHeight * endY);

        marginBottomBegin = beginHeight + originalBottomMargin - expandedHeight;
        marginBottomEnd = endHeight + originalBottomMargin - expandedHeight;
        marginsInitialized = true;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);     

        if (!marginsInitialized && preDrawListener == null) {                       
            // To avoid glitches, don't draw until we've initialized everything.
            preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {                    
                    if (view.getHeight() != 0) {
                        expandedHeight = view.getHeight();
                        initializeMargins();
                        adjustViewBounds(0f);
                        view.getViewTreeObserver().removeOnPreDrawListener(this);                               
                    }

                    return false;
                }
            };

            view.getViewTreeObserver().addOnPreDrawListener(preDrawListener);                   
        }

        if (interpolatedTime < 1.0f && view.getVisibility() != View.VISIBLE) {          
            view.setVisibility(View.VISIBLE);           
        }

        if (marginsInitialized) {           
            if (interpolatedTime < 1.0f) {
                adjustViewBounds(interpolatedTime);
            } else if (endY <= 0f && view.getVisibility() != View.GONE) {               
                view.setVisibility(View.GONE);
            }
        }
    }

    private void adjustViewBounds(float interpolatedTime) {
        layoutParams.bottomMargin = 
                marginBottomBegin + (int) ((marginBottomEnd - marginBottomBegin) * interpolatedTime);       

        view.getParent().requestLayout();
    }
}

Bunu önce mevcut bir LinearLayout'u daraltmak ve ardından aynı LinearLayout'u daha sonra tekrar genişletmek için kullanmak mümkün müdür? Bunu yapmaya çalıştığımda, sadece çöküyor ve tekrar genişlemiyor (muhtemelen görünümün yüksekliği artık 0 olduğu için veya buna benzer bir şey).
AHaahr

Doğrusal düzen birden fazla görünüm içerdiğinde daha güvenilir çalıştığını buldum. Yalnızca bir görünüm içeriyorsa, her zaman genişlemeyecektir.
OpenGL
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.