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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 折叠动画可以使用属性动画来实现。以下是一个简单的实现方式: 1. 定义布局文件 在布局文件中,需要定义两个 View,一个是可见的 View,一个是不可见的 View。可见的 View 用来展示内容,不可见的 View 用来作为展开折叠的目标。 2. 定义属性动画 使用属性动画来实现折叠效果,需要针对可见的 View 的高度进行动画。根据需要展开折叠的高度,设置动画的起始值和结束值。 3. 设置动画监听器 在动画开始和结束时,需要对不可见的 View 进行显示或隐藏。 以下是一个具体的实现例子: 1. 定义布局文件 ```xml <RelativeLayout android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" android:padding="16dp" android:text="Hello World!"/> <TextView android:id="@+id/target" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="gone"/> </RelativeLayout> ``` 2. 定义属性动画 ```java private void animateView(final View view, final int startHeight, final int endHeight) { ValueAnimator valueAnimator = ValueAnimator.ofInt(startHeight, endHeight); valueAnimator.setDuration(500); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int value = (int) animation.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); layoutParams.height = value; view.setLayoutParams(layoutParams); } }); valueAnimator.start(); } ``` 3. 设置动画监听器 ```java private void toggle() { final TextView content = findViewById(R.id.content); final TextView target = findViewById(R.id.target); final int targetHeight = content.getLineHeight() * 3; if (target.getVisibility() == View.GONE) { target.setVisibility(View.VISIBLE); animateView(content, content.getHeight(), targetHeight); } else { animateView(content, targetHeight, content.getHeight()); target.setVisibility(View.GONE); } } ``` 以上是一个简单的实现方式,可以根据实际需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值