Android 如何设置View.setVisibility的动画(已消失)

Android 如何设置View.setVisibility的动画(已消失),android,animation,Android,Animation,我想制作一个动画,当视图的可见性设置为消失时。视图应该“崩溃”,而不仅仅是消失。我用ScaleAnimation尝试了这一点,但是视图是折叠的,但是布局只会在动画停止(或开始)之后(或之前)调整其空间大小 如何制作动画,以便在制作动画时,较低的视图将直接位于内容下方,而不是有一个空白空间?通过API似乎不是一个简单的方法,因为动画只是更改视图的渲染矩阵,而不是实际大小。但是我们可以设置一个负的裕度来愚弄LinearLayout,使其认为视图正在变小 因此,我建议您基于ScaleAnimation

我想制作一个
动画
,当
视图
的可见性设置为
消失时
视图应该“崩溃”,而不仅仅是消失。我用
ScaleAnimation
尝试了这一点,但是
视图是折叠的,但是布局只会在
动画停止(或开始)之后(或之前)调整其空间大小


如何制作
动画
,以便在制作动画时,较低的
视图
将直接位于内容下方,而不是有一个空白空间?

通过API似乎不是一个简单的方法,因为动画只是更改视图的渲染矩阵,而不是实际大小。但是我们可以设置一个负的裕度来愚弄LinearLayout,使其认为视图正在变小

因此,我建议您基于ScaleAnimation创建自己的动画类,并重写“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);
            }
        }

    }

}
公共类Q2634073扩展活动实现OnClickListener{
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.q2634073);
findviewbyd(R.id.item1).setOnClickListener(this);
}
@凌驾
公共void onClick(视图){
view.startAnimation(新的MyScaler(1.0f,1.0f,1.0f,0.0f,500,view,true));
}
公共类MyScaler扩展了ScaleAnimation{
私有视图;
私有布局参数mLayoutParams;
私人内特马尔金波顿弗罗米,马尔金波顿玩具;
私有布尔值mVanishAfter=false;
公共MyScaler(float fromX、float toX、float fromY、float toY、int duration、View、,
布尔消失(后){
超级(fromX,toX,fromY,toY);
设置持续时间(持续时间);
mView=视图;
mVanishAfter=之后消失;
mLayoutParams=(LayoutParams)视图。getLayoutParams();
int height=mView.getHeight();
mMarginBottomFromY=(int)(高度*fromY)+mLayoutParams.bottomMargin-高度;
mMarginBottomToY=(int)(0-((高度*玩具)+mLayoutParams.bottomMargin))-高度;
}
@凌驾
受保护的无效应用转换(浮点插值时间,转换t){
超级应用转换(插值时间,t);
如果(插值时间<1.0f){
int newMarginBottom=mMarginBottomFromY
+(int)((mMarginBottomToY-mMarginBottomFromY)*插值时间);
mLayoutParams.SETMARGIN(mLayoutParams.leftMargin,mLayoutParams.topMargin,
mLayoutParams.righmargin,newMarginBottom);
mView.getParent().requestLayout();
}否则,如果(MVA轴){
mView.setVisibility(View.GONE);
}
}
}
}

通常需要注意的是:因为我们正在覆盖一个受保护的方法(applyTransformation),所以这不能保证在Android的未来版本中起作用。

我使用了与Andy在这里介绍的相同的技术。我为此编写了自己的动画类,该类为边距的值设置动画,使项目的效果消失/出现。 看起来是这样的:

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();
    }
}
}
public类ExpandAnimation扩展动画{
//初始化。。。
@凌驾
受保护的无效应用转换(浮点插值时间,转换t){
超级应用转换(插值时间,t);
如果(插值时间<1.0f){
//计算并设置新的底部边距
mViewLayoutParams.bottomMargin=mMarginStart
+(int)((mMarginEnd-mMarginStart)*插值时间);
//使布局无效,使我们看到所做的更改
mAnimatedView.requestLayout();
}
}
}
我在我的博客上有一个完整的例子

我在这里使用了与Andy相同的技术,并对其进行了改进,使其能够在无故障的情况下用于展开和折叠,还使用了下面描述的技术:

导入android.view.view;
导入android.view.ViewTreeObserver;
导入android.view.animation.ScaleAnimation;
导入android.view.animation.Transformation;
导入android.widget.LinearLayout;
类LinearLayoutVerticalScaleAnimation扩展了ScaleAnimation{
私人最终线性布局视图;
专用最终LinearLayout.LayoutParams LayoutParams;
私人最终浮动开始;
私人最终浮点数;
私人最终内部原始底边;
私用int扩展高度;
private boolean marginInitialized=false;
私人内特马金博顿贝京;
私人保证金;
私有ViewTreeObserver.OnPreDrawListener preDrawListener;
LinearLayoutVerticalScaleAnimation(浮点起始、浮点结束、,
线性布局(线性布局){
超级(1f、1f、beginY、endY);
this.view=linearLayout;
this.layoutParams=(LinearLayout.layoutParams)LinearLayout.getLayoutParams();
this.beginY=beginY;
this.endY=endY;
this.originalBottomMargin=布局参数bottomMargin;
if(view.getHeight()!=0){
expandedHeight=view.getHeight();
initializeMargins();
}
}
私有无效初始值缩写(){
最终整数起始高度=(整数)(展开高度*起始高度);
最终整数endHeight=(整数)(展开高度*endY);
marginBottomBegin=起始高度+原始底部边距-展开高度;
marginBottomEnd=结束高度+原始底部边缘-展开高度;
边际化=真;
}
@凌驾
受保护的无效应用转换(浮点插值时间,转换t){
超级应用转换(插值时间,t);
如果(!marginInitialized&&predrawstener==null){
//
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();
    }
}