android 折叠动画,Android:展开/折叠动画

本文介绍了如何在Android中实现视图的折叠和展开动画,解决在动画开始时可能出现的闪烁问题。提供了多种实现方案,包括使用Animation、ValueAnimator和 interpolators,以及考虑不同Android版本的兼容性。示例代码展示了如何优雅地控制视图的扩展和收缩,以实现平滑过渡效果。
摘要由CSDN通过智能技术生成

Android:展开/折叠动画

假设我有一个垂直linearLayout:

[v1]

[v2]

默认情况下,v1具有visibily = GONE。 我想用扩展动画展示v1并同时向下推v2。

我试过这样的事情:

Animation a = new Animation()

{

int initialHeight;

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

final int newHeight = (int)(initialHeight * interpolatedTime);

v.getLayoutParams().height = newHeight;

v.requestLayout();

}

@Override

public void initialize(int width, int height, int parentWidth, int parentHeight) {

super.initialize(width, height, parentWidth, parentHeight);

initialHeight = height;

}

@Override

public boolean willChangeBounds() {

return true;

}

};

但是使用这个解决方案,动画开始时我会闪烁。 我认为这是由v1在应用动画之前显示完整大小引起的。

使用javascript,这是一行jQuery! 用android做任何简单的方法吗?

30个解决方案

665 votes

我看到这个问题变得流行,所以我发布了我的实际解决方案。 主要优点是您不必知道应用动画的扩展高度,并且一旦展开视图,它会在内容更改时调整高度。 这对我很有效。

public static void expand(final View v) {

v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);

final int targetHeight = v.getMeasuredHeight();

// Older versions of android (pre API 21) cancel animations for views with a height of 0.

v.getLayoutParams().height = 1;

v.setVisibility(View.VISIBLE);

Animation a = new Animation()

{

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

v.getLayoutParams().height = interpolatedTime == 1

? LayoutParams.WRAP_CONTENT

: (int)(targetHeight * interpolatedTime);

v.requestLayout();

}

@Override

public boolean willChangeBounds() {

return true;

}

};

// 1dp/ms

a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));

v.startAnimation(a);

}

public static void collapse(final View v) {

final int initialHeight = v.getMeasuredHeight();

Animation a = new Animation()

{

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

if(interpolatedTime == 1){

v.setVisibility(View.GONE);

}else{

v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);

v.requestLayout();

}

}

@Override

public boolean willChangeBounds() {

return true;

}

};

// 1dp/ms

a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));

v.startAnimation(a);

}

Tom Esterez answered 2019-03-31T02:27:05Z

139 votes

我试图做我认为是一个非常相似的动画,并找到了一个优雅的解决方案。 此代码假定您始终从0-> h或h-> 0(h是最大高度)。 三个构造函数参数是view =要动画的视图(在我的例子中是webview),targetHeight =视图的最大高度,down =一个指定方向的布尔值(true = expanded,false = collapsing)。

public class DropDownAnim extends Animation {

private final int targetHeight;

private final View view;

private final boolean down;

public DropDownAnim(View view, int targetHeight, boolean down) {

this.view = view;

this.targetHeight = targetHeight;

this.down = down;

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

int newHeight;

if (down) {

newHeight = (int) (targetHeight * interpolatedTime);

} else {

newHeight = (int) (targetHeight * (1 - interpolatedTime));

}

view.getLayoutParams().height = newHeight;

view.requestLayout();

}

@Override

public void initialize(int width, int height, int parentWidth,

int parentHeight) {

super.initialize(width, height, parentWidth, parentHeight);

}

@Override

public boolean willChangeBounds() {

return true;

}

}

Seth Nelson answered 2019-03-31T02:27:30Z

120 votes

我今天偶然发现了同样的问题,我想这个问题的真正解决方案就是这个

android:animateLayoutChanges="true"

...

/>

您必须为所有最顶层布局设置此属性,这些布局涉及移位。 如果您现在将一个布局的可见性设置为GONE,另一个将占用空间,因为消失的布局将释放它。 将会有一个默认动画,它是某种“淡出”,但我认为你可以改变它 - 但是现在我还没有测试过的最后一个。

Mr.Fu answered 2019-03-31T02:28:01Z

54 votes

我采用了@LenaYan的解决方案,但效果不正常对我来说(因为它在折叠和/或扩展之前将视图转换为0高度视图)并进行了一些更改。

现在,通过获取View的先前高度并开始使用此大小进行扩展,效果很好。 折叠是一样的。

您只需复制并粘贴以下代码即可:

public static void expand(final View v, int duration, int targetHeight) {

int prevHeight = v.getHeight();

v.setVisibility(View.VISIBLE);

ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

v.getLayoutParams().height = (int) animation.getAnimatedValue();

v.requestLayout();

}

});

valueAnimator.setInterpolator(new DecelerateInterpolator());

valueAnimator.setDuration(duration);

valueAnimator.start();

}

public static void collapse(final View v, int duration, int targetHeight) {

int prevHeight = v.getHeight();

ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);

valueAnimator.setInterpolator(new DecelerateInterpolator());

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

v.getLayoutParams().height = (int) animation.getAnimatedValue();

v.requestLayout();

}

});

valueAnimator.setInterpolator(new DecelerateInterpolator());

valueAnimator.setDuration(duration);

valueAnimator.start();

}

用法:

//Expanding the View

expand(yourView, 2000, 200);

// Collapsing the View

collapse(yourView, 2000, 100);

够容易!

感谢LenaYan的初始代码!

Geraldo Neto answered 2019-03-31T02:28:55Z

39 votes

另一种方法是使用具有以下缩放因子的缩放动画进行扩展:

ScaleAnimation anim = new ScaleAnimation(1, 1, 0, 1);

和折叠:

ScaleAnimation anim = new ScaleAnimation(1, 1, 1, 0);

ChristophK answered 2019-03-31T02:29:26Z

25 votes

好的,我刚刚发现了一个非常难看的解决方案:

public static Animation expand(final View v, Runnable onEnd) {

try {

Method m = v.getClass().getDeclaredMethod("onMeasure", int.class, int.class);

m.setAccessible(true);

m.invoke(

v,

MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),

MeasureSpec.makeMeasureSpec(((View)v.getParent()).getMeasuredHeight(), MeasureSpec.AT_MOST)

);

} catch (Exception e){

Log.e("test", "", e);

}

final int initialHeight = v.getMeasuredHeight();

Log.d("test", "initialHeight="+initialHeight);

v.getLayoutParams().height = 0;

v.setVisibility(View.VISIBLE);

Animation a = new Animation()

{

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

final int newHeight = (int)(initialHeight * interpolatedTime);

v.getLayoutParams().height = newHeight;

v.requestLayout();

}

@Override

public boolean willChangeBounds() {

return true;

}

};

a.setDuration(5000);

v.startAnimation(a);

return a;

}

随意提出更好的解决方案!

Tom Esterez answered 2019-03-31T02:29:57Z

24 votes

@Tom Esterez的答案,但更新为正确使用view.measure()每个Android getMeasuredHeight返回错误的值!

// http://easings.net/

Interpolator easeInOutQuart = PathInterpolatorCompat.create(0.77f, 0f, 0.175f, 1f);

public static Animation expand(final View view) {

int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) view.getParent()).getWidth(), View.MeasureSpec.EXACTLY);

int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);

view.measure(matchParentMeasureSpec, wrapContentMeasureSpec);

final int targetHeight = view.getMeasuredHeight();

// Older versions of android (pre API 21) cancel animations for views with a height of 0 so use 1 instead.

view.getLayoutParams().height = 1;

view.setVisibility(View.VISIBLE);</

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值