Android 我如何动画 View.setVisibility(GONE)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2634073/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I animate View.setVisibility(GONE)
提问by MrSnowflake
I want to make an Animation
for when a View
gets it's visibility set to GONE
. Instead of just dissapearing, the View
should 'collapse'. I tried this with a ScaleAnimation
but then the View
is collapse, but the layout will only resize it's space after (or before) the Animation
stops (or starts).
我想Animation
在 aView
将其可见性设置为GONE
. View
应该“崩溃”而不是仅仅消失。我尝试了这个,ScaleAnimation
但是然后View
是崩溃,但是布局只会在Animation
停止(或开始)之后(或之前)调整它的空间大小。
How can I make the Animation
so that, while animating, the lower View
s will stay directly below the content, instead of having a blank space?
我怎样才能使sAnimation
动画时,较低的View
s 将直接留在内容下方,而不是有一个空格?
采纳答案by Andy
There doesn't seem to be an easy way to do this through the API, because the animation just changes the rendering matrix of the view, not the actual size. But we can set a negative margin to fool LinearLayout into thinking that the view is getting smaller.
通过 API 似乎没有一种简单的方法可以做到这一点,因为动画只是改变了视图的渲染矩阵,而不是实际大小。但是我们可以设置一个负边距来欺骗 LinearLayout 认为视图正在变小。
So I'd recommend creating your own Animation class, based on ScaleAnimation, and overriding the "applyTransformation" method to set new margins and update the layout. Like this...
因此,我建议基于 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);
}
}
}
}
The usual caveat applies: because we are overriding a protected method (applyTransformation), this is not guaranteed to work in future versions of Android.
通常的警告适用:因为我们覆盖了一个受保护的方法 (applyTransformation),所以不能保证在未来的 Android 版本中工作。
回答by Vinay W
Put the view in a layout if it's not and set android:animateLayoutChanges="true"
for that layout.
如果不是,则将视图放在布局中并android:animateLayoutChanges="true"
为该布局设置。
回答by Udinic
I used the same technique as Andy here has presented. I wrote my own Animation class for that, that animate the margin's value, causing the effect of the item to disappear/appear. It looks like this:
我使用了与安迪在这里介绍的相同的技术。我为此编写了自己的 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();
}
}
}
I have a full example that works on my blog post http://udinic.wordpress.com/2011/09/03/expanding-listview-items/
我有一个完整的例子,适用于我的博客文章 http://udinic.wordpress.com/2011/09/03/expanding-listview-items/
回答by Learn OpenGL ES
I used the same technique as Andy here, and refined it so that it can be used for expanding and collapsing without glitches, also using a technique described here: https://stackoverflow.com/a/11426510/1317564
我在这里使用了与 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();
}
}