Wie animiere ich View.setVisibility (GONE)

84

Ich möchte ein Animationfür machen, wenn a Viewseine Sichtbarkeit eingestellt bekommt GONE. Anstatt nur zu verschwinden, Viewsollte das "zusammenbrechen". Ich habe dies mit einem versucht, ScaleAnimationaber dann Viewist der Zusammenbruch, aber das Layout ändert nur die Größe seines Speicherplatzes nach (oder vor) den AnimationStopps (oder Starts).

Wie kann ich das Animationso gestalten, dass beim Animieren die unteren Views direkt unter dem Inhalt bleiben, anstatt ein Leerzeichen zu haben?

MrSnowflake
quelle
Ich habe die gleiche Technik verwendet, die Andy hier in meiner ExpandAnimation vorgestellt hat: udinic.wordpress.com/2011/09/03/expanding-listview-items Ich habe keine Skalierungsanimation verwendet, sondern nur eine neue Animation erstellt Klasse dafür.
Udinic
Dies war sehr nützlich, als ich dies versuchte. Vielen Dank
atraudes
Ausgezeichnete Udinic .. wirklich mein Problem gelöst .. :) danke
Yousuf Qureshi
Großartig, ich muss mich an mein Problem anpassen, aber am Ende funktioniert es. Für mich war diese Lösung besser als die andere Antwort.
Derzu

Antworten:

51

Es scheint keine einfache Möglichkeit zu geben, dies über die API zu tun, da die Animation nur die Rendermatrix der Ansicht ändert, nicht die tatsächliche Größe. Wir können jedoch einen negativen Spielraum festlegen, um LinearLayout zu täuschen, dass die Ansicht kleiner wird.

Daher würde ich empfehlen, eine eigene Animationsklasse basierend auf ScaleAnimation zu erstellen und die Methode "applyTransformation" zu überschreiben, um neue Ränder festzulegen und das Layout zu aktualisieren. So was...

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

    }

}

Es gilt die übliche Einschränkung: Da wir eine geschützte Methode (applyTransformation) überschreiben, kann nicht garantiert werden, dass dies in zukünftigen Versionen von Android funktioniert.

Andy
quelle
3
Warum zum Teufel habe ich nicht daran gedacht?! Danke dir. Außerdem verstehe ich nicht: "Es gilt die übliche Einschränkung: Da wir eine geschützte Methode (applyTransformation) überschreiben, kann dies in zukünftigen Android-Versionen nicht garantiert funktionieren." - Warum unterscheiden sich geschützte Funktionen zwischen API-Versionen? Diese sind nicht ausgeblendet und werden geschützt implementiert, damit Sie sie überschreiben können (andernfalls würden sie einen Paketbereich haben).
MrSnowflake
Sie haben wahrscheinlich Recht mit der geschützten Methode. Ich neige dazu, beim Zugriff auf sie in einer API übervorsichtig zu sein.
Andy
1
Dies funktionierte hervorragend für mich, außer dass ich das 0 - in der marginBottomToYBerechnung entfernen musste, um das "Zusammenfallen" zum Laufen zu bringen (von Y = 0,0f bis Y = 1,0f) .
dmon
2
Ich würde vorschlagen, den generischen Typ zu verwenden, MarginLayoutParamsanstatt ihn in einen bestimmten LayoutParamTyp umzuwandeln.
Paul Lammertsma
3
Angenommen, ich muss die Animation umschalten, und wie könnte ich das umgekehrt machen? Bitte beraten.
Umesh
99

Fügen Sie die Ansicht in ein Layout ein, wenn dies nicht der Fall ist, und legen Sie sie android:animateLayoutChanges="true"für dieses Layout fest.

Vinay W.
quelle
1
Min. API erforderlich ist 11 oder höher! Diese Methode kann nicht für niedrigere Versionen verwendet werden.
Nagaraj Alagusudaram
2
Dies ist das am meisten unterschätzte Layout-Attribut ... danke!
Andres Santiago
7

Ich habe die gleiche Technik verwendet, die Andy hier vorgestellt hat. Ich habe dafür meine eigene Animationsklasse geschrieben, die den Wert des Randes animiert und bewirkt, dass der Effekt des Elements verschwindet / erscheint. Es sieht aus wie das:

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

Ich habe ein vollständiges Beispiel, das in meinem Blog-Beitrag http://udinic.wordpress.com/2011/09/03/expanding-listview-items/ funktioniert.

Udinic
quelle
2

Ich habe hier dieselbe Technik wie Andy verwendet und sie so verfeinert, dass sie ohne Störungen erweitert und reduziert werden kann, auch mit einer hier beschriebenen Technik: 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();
    }
}
Lernen Sie OpenGL ES
quelle
Ist es möglich, damit zuerst ein vorhandenes LinearLayout zu reduzieren und anschließend dasselbe LinearLayout erneut zu erweitern? Wenn ich das versuche, wird es einfach zusammengeklappt und nicht wieder erweitert (wahrscheinlich, weil die Höhe der Ansicht jetzt 0 ist oder so ähnlich).
AHaahr
Ich habe festgestellt, dass es zuverlässiger funktioniert, wenn das lineare Layout mehr als eine Ansicht enthält. Wenn es nur eine Ansicht enthält, wird es nicht immer erweitert.
Lernen Sie OpenGL ES