View.setVisibility(GONE)をアニメーション化するにはどうすればよいですか


84

可視性がに設定されたAnimationときのforを作成したいと思います。単に消えるのではなく、「崩壊」する必要があります。これを試してみましたが、は折りたたまれていますが、レイアウトは停止(または開始)後(または開始前)にのみスペースのサイズを変更します。ViewGONEViewScaleAnimationViewAnimation

Animationアニメーション化中に、下部Viewのsが空白ではなく、コンテンツの真下にとどまるようにするにはどうすればよいですか?


ここでAndyが提示したのと同じ手法を、ExpandAnimationで使用しました:udinic.wordpress.com/2011/09/03/expanding-listview-itemsスケールアニメーションを使用せず、新しいアニメーションを作成しましたそのためのクラス。
Udinic 2011

これをやろうとしている間、これは非常に役に立ちました。ありがとう
2011

優れたUdinic ..本当に私の問題を解決しました.. :)ありがとう
Yousuf Qureshi

素晴らしいです。問題に適応する必要がありますが、最終的には機能します。私にとって、この解決策は他の答えよりも優れていました。
derzu 2012

回答:


51

アニメーションは実際のサイズではなく、ビューのレンダリングマトリックスを変更するだけなので、APIを介してこれを行う簡単な方法はないようです。ただし、LinearLayoutをだまして、ビューが小さくなっていると思わせるために、負のマージンを設定することはできます。

したがって、ScaleAnimationに基づいて独自のAnimationクラスを作成し、「applyTransformation」メソッドをオーバーライドして新しいマージンを設定し、レイアウトを更新することをお勧めします。このような...

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

    }

}

通常の警告が適用されます。保護されたメソッド(applyTransformation)をオーバーライドしているため、これはAndroidの将来のバージョンで機能することが保証されていません。


3
なんでこんなこと考えなかったの?ありがとうございました。また、「通常の警告が適用されます。保護されたメソッド(applyTransformation)をオーバーライドしているため、これがAndroidの将来のバージョンで機能することは保証されていません。」-保護された関数がAPIバージョン間で異なるのはなぜですか?それらは非表示ではなく、保護されて実装されているため、オーバーライドできます(そうでない場合は、パッケージスコープになります)。
MrSnowflake 2010年

あなたはおそらく保護された方法について正しいでしょう。私はAPIでそれらにアクセスすることについて過度に慎重になる傾向があります。
アンディ

1
これは、「折りたたみ」を機能させる(fromY = 0.0f、toY = 1.0f)ことを除いて、私にとってはうまく機能し0 - ましたmarginBottomToY。計算でを削除する必要がありました。
dmon 2011年

2
MarginLayoutParams特定のLayoutParam型にキャストするのではなく、ジェネリック型を使用することをお勧めします。
Paul Lammertsma 2013

3
トグルアニメーションを実行する必要があるとすると、逆に実行するにはどうすればよいでしょうか。アドバイスを下さい。
Umesh 2015

99

そうでない場合は、ビューandroid:animateLayoutChanges="true"をレイアウトに配置し、そのレイアウトに設定します。


1
必要な最小APIは11以上です!下位バージョンではこのメソッドを使用できません。
ナガラジアラグスダラム2014年

2
これは最も過小評価されているレイアウト属性です...ありがとうございます!
アンドレスサンティアゴ

7

ここでアンディが提示したのと同じテクニックを使用しました。そのために独自のAnimationクラスを作成しました。これは、マージンの値をアニメーション化して、アイテムの効果を消したり表示したりします。次のようになります。

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

私のブログ投稿http://udinic.wordpress.com/2011/09/03/expanding-listview-items/で機能する完全な例があります


2

ここではAndyと同じ手法を使用し、グリッチなしで拡張および折りたたみに使用できるように改良しました。また、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();
    }
}

これを使用して、最初に既存のLinearLayoutを折りたたんでから、同じLinearLayoutを後で再度展開することは可能ですか?これを実行しようとすると、折りたたまれて再び拡大することはありません(おそらく、ビューの高さが0などになっているためです)。
AHaahr 2013年

線形レイアウトに複数のビューが含まれていると、より確実に機能することがわかりました。ビューが1つしかない場合は、常に展開されるとは限りません。
OpenGLESを学ぶ2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.