失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > android 折叠动画 Android:展开/折叠动画

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

时间:2024-04-11 21:08:31

相关推荐

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 -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 -03-31T02:27:30Z

120 votes

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

android:animateLayoutChanges="true"

...

/>

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

Mr.Fu answered -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 -03-31T02:28:55Z

39 votes

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

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

和折叠:

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

ChristophK answered -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 -03-31T02:29:57Z

24 votes

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

// /

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

Animation animation = new Animation() {

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

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

? ViewGroup.LayoutParams.WRAP_CONTENT

: (int) (targetHeight * interpolatedTime);

view.requestLayout();

}

@Override

public boolean willChangeBounds() {

return true;

}

};

animation.setInterpolator(easeInOutQuart);

animation.setDuration(computeDurationFromHeight(view));

view.startAnimation(animation);

return animation;

}

public static Animation collapse(final View view) {

final int initialHeight = view.getMeasuredHeight();

Animation a = new Animation() {

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

if (interpolatedTime == 1) {

view.setVisibility(View.GONE);

} else {

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

view.requestLayout();

}

}

@Override

public boolean willChangeBounds() {

return true;

}

};

a.setInterpolator(easeInOutQuart);

int durationMillis = computeDurationFromHeight(view);

a.setDuration(durationMillis);

view.startAnimation(a);

return a;

}

private static int computeDurationFromHeight(View view) {

// 1dp/ms * multiplier

return (int) (view.getMeasuredHeight() / view.getContext().getResources().getDisplayMetrics().density);

}

Erik B answered -03-31T02:30:22Z

20 votes

如果你不想一直扩展或折叠 - 这里是一个简单的高度动画 -

import android.view.View;

import android.view.animation.Animation;

import android.view.animation.Transformation;

public class HeightAnimation extends Animation {

protected final int originalHeight;

protected final View view;

protected float perValue;

public HeightAnimation(View view, int fromHeight, int toHeight) {

this.view = view;

this.originalHeight = fromHeight;

this.perValue = (toHeight - fromHeight);

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

view.getLayoutParams().height = (int) (originalHeight + perValue * interpolatedTime);

view.requestLayout();

}

@Override

public boolean willChangeBounds() {

return true;

}

}

用法:

HeightAnimation heightAnim = new HeightAnimation(view, view.getHeight(), viewPager.getHeight() - otherView.getHeight());

heightAnim.setDuration(1000);

view.startAnimation(heightAnim);

Nir Hartmann answered -03-31T02:30:48Z

20 votes

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

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

v.getLayoutParams().height = 0;

v.setVisibility(View.VISIBLE);

ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 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) {

ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 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();

}

LenaYan answered -03-31T02:31:05Z

6 votes

我想在上面的非常有用的答案中添加一些内容。 如果您不知道自从您的视图.getHeight()返回0后您将最终得到的高度,您可以执行以下操作来获得高度:

contentView.measure(DUMMY_HIGH_DIMENSION, DUMMY_HIGH_DIMENSION);

int finalHeight = view.getMeasuredHeight();

其中DUMMY_HIGH_DIMENSIONS是宽度/高度(以像素为单位),您的视图被约束为......当使用ScrollView封装视图时,这个数字很大是合理的。

gardarh answered -03-31T02:31:37Z

6 votes

这是我用于通过动画调整视图宽度(LinearLayout)的片段。

代码应根据目标大小进行扩展或缩小。 如果需要fill_parent宽度,则必须将父.getMeasuredWidth作为目标宽度传递,同时将标志设置为true。

希望它对你们有些帮助。

public class WidthResizeAnimation extends Animation {

int targetWidth;

int originaltWidth;

View view;

boolean expand;

int newWidth = 0;

boolean fillParent;

public WidthResizeAnimation(View view, int targetWidth, boolean fillParent) {

this.view = view;

this.originaltWidth = this.view.getMeasuredWidth();

this.targetWidth = targetWidth;

newWidth = originaltWidth;

if (originaltWidth > targetWidth) {

expand = false;

} else {

expand = true;

}

this.fillParent = fillParent;

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

if (expand && newWidth < targetWidth) {

newWidth = (int) (newWidth + (targetWidth - newWidth) * interpolatedTime);

}

if (!expand && newWidth > targetWidth) {

newWidth = (int) (newWidth - (newWidth - targetWidth) * interpolatedTime);

}

if (fillParent && interpolatedTime == 1.0) {

view.getLayoutParams().width = -1;

} else {

view.getLayoutParams().width = newWidth;

}

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;

}

}

Codewarrior answered -03-31T02:32:17Z

6 votes

对于平滑动画,请使用Handler with run method .....并享受展开/折叠动画

class AnimUtils{

public void expand(final View v) {

int ANIMATION_DURATION=500;//in milisecond

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

final int targtetHeight = v.getMeasuredHeight();

v.getLayoutParams().height = 0;

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)(targtetHeight * interpolatedTime);

v.requestLayout();

}

@Override

public boolean willChangeBounds() {

return true;

}

};

// 1dp/ms

a.setDuration(ANIMATION_DURATION);

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

v.startAnimation(a);

}

public 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(ANIMATION_DURATION);

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

v.startAnimation(a);

}

}

并使用此代码调用:

private void setAnimationOnView(final View inactive ) {

//I am applying expand and collapse on this TextView ...You can use your view

//for expand animation

new Handler().postDelayed(new Runnable() {

@Override

public void run() {

new AnimationUtililty().expand(inactive);

}

}, 1000);

//For collapse

new Handler().postDelayed(new Runnable() {

@Override

public void run() {

new AnimationUtililty().collapse(inactive);

//inactive.setVisibility(View.GONE);

}

}, 8000);

}

其他解决方案是:

public void expandOrCollapse(final View v,String exp_or_colpse) {

TranslateAnimation anim = null;

if(exp_or_colpse.equals("expand"))

{

anim = new TranslateAnimation(0.0f, 0.0f, -v.getHeight(), 0.0f);

v.setVisibility(View.VISIBLE);

}

else{

anim = new TranslateAnimation(0.0f, 0.0f, 0.0f, -v.getHeight());

AnimationListener collapselistener= new AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

}

@Override

public void onAnimationRepeat(Animation animation) {

}

@Override

public void onAnimationEnd(Animation animation) {

v.setVisibility(View.GONE);

}

};

anim.setAnimationListener(collapselistener);

}

// To Collapse

//

anim.setDuration(300);

anim.setInterpolator(new AccelerateInterpolator(0.5f));

v.startAnimation(anim);

}

Ashish Saini answered -03-31T02:32:57Z

6 votes

除了Tom Esterez的优秀答案和Erik B对它的出色更新之外,我想我会发布自己的看法,将扩展和合同方法压缩成一个。 这样,您可以举例如此...

button.setOnClickListener(v -> expandCollapse(view));

...调用下面的方法并让它弄清楚每个onClick()之后要做什么...

public static void expandCollapse(View view) {

boolean expand = view.getVisibility() == View.GONE;

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

view.measure(

View.MeasureSpec.makeMeasureSpec(((View) view.getParent()).getWidth(), View.MeasureSpec.EXACTLY),

View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)

);

int height = view.getMeasuredHeight();

int duration = (int) (height/view.getContext().getResources().getDisplayMetrics().density);

Animation animation = new Animation() {

@Override protected void applyTransformation(float interpolatedTime, Transformation t) {

if (expand) {

view.getLayoutParams().height = 1;

view.setVisibility(View.VISIBLE);

if (interpolatedTime == 1) {

view.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;

} else {

view.getLayoutParams().height = (int) (height * interpolatedTime);

}

view.requestLayout();

} else {

if (interpolatedTime == 1) {

view.setVisibility(View.GONE);

} else {

view.getLayoutParams().height = height - (int) (height * interpolatedTime);

view.requestLayout();

}

}

}

@Override public boolean willChangeBounds() {

return true;

}

};

animation.setInterpolator(easeInOutQuart);

animation.setDuration(duration);

view.startAnimation(animation);

}

mjp66 answered -03-31T02:33:29Z

5 votes

我认为最简单的解决方案是将android:animateLayoutChanges="true"设置为LinearLayout,然后通过设置其可见性来显示/隐藏视图。 像魅力一样工作,但你无法控制动画的持续时间

Jacek Kwiecień answered -03-31T02:33:54Z

4 votes

是的,我同意上述评论。 事实上,似乎正确(或至少最简单?)的事情是指定(在XML中)初始布局高度“0px” - 然后你可以传入“toHeight”的另一个参数( 即自定义动画子类的构造函数的“最终高度”,例如 在上面的例子中,它看起来像这样:

public DropDownAnim( View v, int toHeight ) { ... }

无论如何,希望有所帮助!:)

Daniel Kopyc answered -03-31T02:34:26Z

4 votes

这是我的解决方案。 我认为这更简单。 它只扩展了视图,但可以轻松扩展。

public class WidthExpandAnimation extends Animation

{

int _targetWidth;

View _view;

public WidthExpandAnimation(View view)

{

_view = view;

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t)

{

if (interpolatedTime < 1.f)

{

int newWidth = (int) (_targetWidth * interpolatedTime);

_view.layout(_view.getLeft(), _view.getTop(),

_view.getLeft() + newWidth, _view.getBottom());

}

else

_view.requestLayout();

}

@Override

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

{

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

_targetWidth = width;

}

@Override

public boolean willChangeBounds() {

return true;

}

}

Kaloyan Donev answered -03-31T02:34:51Z

4 votes

来自@Tom Esterez和@Geraldo Neto的综合解决方案

public static void expandOrCollapseView(View v,boolean expand){

if(expand){

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

final int targetHeight = v.getMeasuredHeight();

v.getLayoutParams().height = 0;

v.setVisibility(View.VISIBLE);

ValueAnimator valueAnimator = ValueAnimator.ofInt(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(500);

valueAnimator.start();

}

else

{

final int initialHeight = v.getMeasuredHeight();

ValueAnimator valueAnimator = ValueAnimator.ofInt(initialHeight,0);

valueAnimator.setInterpolator(new DecelerateInterpolator());

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

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

v.requestLayout();

if((int)animation.getAnimatedValue() == 0)

v.setVisibility(View.GONE);

}

});

valueAnimator.setInterpolator(new DecelerateInterpolator());

valueAnimator.setDuration(500);

valueAnimator.start();

}

}

//sample usage

expandOrCollapseView((Your ViewGroup),(Your ViewGroup).getVisibility()!=View.VISIBLE);

Flux answered -03-31T02:35:15Z

3 votes

你走在正确的轨道上。 确保在动画开始之前将v1设置为具有零布局高度。 您希望在开始动画之前将设置初始化为动画的第一帧。

Micah Hainline answered -03-31T02:35:41Z

3 votes

确保在动画开始之前将v1设置为具有零布局高度。 您希望在开始动画之前将设置初始化为动画的第一帧。

NhamPD answered -03-31T02:36:05Z

3 votes

这是我的解决方案,我的setAnimationGrowShrink()从setAnimationGrowShrink()增长到200%并返回到原始大小,使用res/anim/文件夹中的两个动画文件

anim_grow.xml

android:interpolator="@android:anim/accelerate_interpolator">

android:fromXScale="1.0"

android:toXScale="2.0"

android:fromYScale="1.0"

android:toYScale="2.0"

android:duration="3000"

android:pivotX="50%"

android:pivotY="50%"

android:startOffset="2000" />

anim_shrink.xml

android:interpolator="@android:anim/accelerate_interpolator">

android:fromXScale="2.0"

android:toXScale="1.0"

android:fromYScale="2.0"

android:toYScale="1.0"

android:duration="3000"

android:pivotX="50%"

android:pivotY="50%"

android:startOffset="2000" />

发送setAnimationGrowShrink()到我的方法setAnimationGrowShrink()

ImageView img1 = (ImageView)findViewById(R.id.image1);

setAnimationGrowShrink(img1);

setAnimationGrowShrink()方法:

private void setAnimationGrowShrink(final ImageView imgV){

final Animation animationEnlarge = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_grow);

final Animation animationShrink = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_shrink);

imgV.startAnimation(animationEnlarge);

animationEnlarge.setAnimationListener(new AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {}

@Override

public void onAnimationRepeat(Animation animation) {}

@Override

public void onAnimationEnd(Animation animation) {

imgV.startAnimation(animationShrink);

}

});

animationShrink.setAnimationListener(new AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {}

@Override

public void onAnimationRepeat(Animation animation) {}

@Override

public void onAnimationEnd(Animation animation) {

imgV.startAnimation(animationEnlarge);

}

});

}

Jorgesys answered -03-31T02:36:59Z

2 votes

这对droidQuery来说非常简单。 对于开始,请考虑以下布局:

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="vertical" >

android:id="@+id/v1"

android:layout_width="wrap_content"

android:layout_height="wrap_content" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="View 1" />

android:id="@+id/v2"

android:layout_width="wrap_content"

android:layout_height="0dp" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="View 2" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="View 3" />

我们可以使用以下代码将高度设置为所需的值 - 例如AnimationOptions:

//convert 100dp to pixel value

int height = (int) TypedValue.applyDimension(PLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());

然后使用AnimationOptions进行动画处理。 最简单的方法是:

$.animate("{ height: " + height + "}", new AnimationOptions());

要使动画更具吸引力,请考虑添加缓动:

$.animate("{ height: " + height + "}", new AnimationOptions().easing($.Easing.BOUNCE));

您还可以使用duration()方法更改AnimationOptions上的持续时间,或处理动画结束时发生的情况。 有关复杂示例,请尝试:

$.animate("{ height: " + height + "}", new AnimationOptions().easing($.Easing.BOUNCE)

.duration(1000)

.complete(new Function() {

@Override

public void invoke($ d, Object... args) {

$.toast(context, "finished", Toast.LENGTH_SHORT);

}

}));

Phil answered -03-31T02:37:53Z

2 votes

展开/折叠视图的最佳解决方案:

@Override

public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

View view = buttonView.getId() == R.id.tb_search ? fSearch : layoutSettings;

transform(view, 200, isChecked

? ViewGroup.LayoutParams.WRAP_CONTENT

: 0);

}

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

int prevHeight = v.getHeight();

v.setVisibility(View.VISIBLE);

ValueAnimator animator;

if (targetHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {

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

animator = ValueAnimator.ofInt(prevHeight, v.getMeasuredHeight());

} else {

animator = ValueAnimator.ofInt(prevHeight, targetHeight);

}

animator.addUpdateListener(animation -> {

v.getLayoutParams().height = (animation.getAnimatedFraction() == 1.0f)

? targetHeight

: (int) animation.getAnimatedValue();

v.requestLayout();

});

animator.setInterpolator(new LinearInterpolator());

animator.setDuration(duration);

animator.start();

}

Владислав Стариков answered -03-31T02:38:20Z

2 votes

您可以轻微使用ViewPropertyAnimator。 要折叠,请将视图缩放到1像素的高度,然后将其隐藏。 要展开,展示它,然后将其展开到它的高度。

private void collapse(final View view) {

view.setPivotY(0);

view.animate().scaleY(1/view.getHeight()).setDuration(1000).withEndAction(new Runnable() {

@Override public void run() {

view.setVisibility(GONE);

}

});

}

private void expand(View view, int height) {

float scaleFactor = height / view.getHeight();

view.setVisibility(VISIBLE);

view.setPivotY(0);

view.animate().scaleY(scaleFactor).setDuration(1000);

}

枢轴告诉视图从哪里缩放,默认位于中间。 持续时间是可选的(默认值= 1000)。 您也可以设置插值器,如.setInterpolator(new AccelerateDecelerateInterpolator())

GLee answered -03-31T02:38:54Z

2 votes

这是一个正确的工作解决方案,我测试过它:

扩大:

private void expand(View v) {

v.setVisibility(View.VISIBLE);

v.measure(View.MeasureSpec.makeMeasureSpec(PARENT_VIEW.getWidth(), View.MeasureSpec.EXACTLY),

View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

final int targetHeight = v.getMeasuredHeight();

mAnimator = slideAnimator(0, targetHeight);

mAnimator.setDuration(800);

mAnimator.start();

}

坍方:

private void collapse(View v) {

int finalHeight = v.getHeight();

mAnimator = slideAnimator(finalHeight, 0);

mAnimator.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animator) {

}

@Override

public void onAnimationEnd(Animator animator) {

//Height=0, but it set visibility to GONE

llDescp.setVisibility(View.GONE);

}

@Override

public void onAnimationCancel(Animator animator) {

}

@Override

public void onAnimationRepeat(Animator animator) {

}

});

mAnimator.start();

}

价值动画师:

private ValueAnimator slideAnimator(int start, int end) {

ValueAnimator mAnimator = ValueAnimator.ofInt(start, end);

mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator valueAnimator) {

//Update Height

int value = (Integer) valueAnimator.getAnimatedValue();

ViewGroup.LayoutParams layoutParams = llDescp.getLayoutParams();

layoutParams.height = value;

v.setLayoutParams(layoutParams);

}

});

return mAnimator;

}

视图v是要动画的视图,PARENT_VIEW是包含视图的容器视图。

Anubhav answered -03-31T02:39:43Z

1 votes

我创建了一个版本,您无需指定布局高度,因此使用起来更简单,更清晰。 解决方案是在动画的第一帧中获得高度(当时可用,至少在我的测试期间)。 这样,您可以提供具有任意高度和底部边距的视图。

构造函数中还有一个小的hack - 底部边距设置为-10000,以便视图在转换之前保持隐藏(防止闪烁)。

public class ExpandAnimation extends Animation {

private View mAnimatedView;

private ViewGroup.MarginLayoutParams mViewLayoutParams;

private int mMarginStart, mMarginEnd;

public ExpandAnimation(View view) {

mAnimatedView = view;

mViewLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();

mMarginEnd = mViewLayoutParams.bottomMargin;

mMarginStart = -10000; //hide before viewing by settings very high negative bottom margin (hack, but works nicely)

mViewLayoutParams.bottomMargin = mMarginStart;

mAnimatedView.setLayoutParams(mViewLayoutParams);

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

super.applyTransformation(interpolatedTime, t);

//view height is already known when the animation starts

if(interpolatedTime==0){

mMarginStart = -mAnimatedView.getHeight();

}

mViewLayoutParams.bottomMargin = (int)((mMarginEnd-mMarginStart) * interpolatedTime)+mMarginStart;

mAnimatedView.setLayoutParams(mViewLayoutParams);

}

}

Michał K answered -03-31T02:40:17Z

1 votes

使用ValueAnimator:

ValueAnimator expandAnimation = ValueAnimator.ofInt(mainView.getHeight(), 400);

expandAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(final ValueAnimator animation) {

int height = (Integer) animation.getAnimatedValue();

RelativeLayout.LayoutParams lp = (LayoutParams) mainView.getLayoutParams();

lp.height = height;

}

});

expandAnimation.setDuration(500);

expandAnimation.start();

Jon answered -03-31T02:40:43Z

1 votes

根据@Tom Esterez和@Seth Nelson(前2名)的解决方案,我对它们进行了解释。 与原始解决方案一样,它不依赖于开发人员选项(动画设置)。

private void resizeWithAnimation(final View view, int duration, final int targetHeight) {

final int initialHeight = view.getMeasuredHeight();

final int distance = targetHeight - initialHeight;

Animation a = new Animation() {

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

if (interpolatedTime == 1 && targetHeight == 0) {

view.setVisibility(View.GONE);

} else {

view.getLayoutParams().height = (int) (initialHeight + distance * interpolatedTime);

view.requestLayout();

}

}

@Override

public boolean willChangeBounds() {

return true;

}

};

a.setDuration(duration);

view.startAnimation(a);

}

CoolMind answered -03-31T02:41:11Z

1 votes

public static void slide(View v, int speed, int pos) {

v.animate().setDuration(speed);

v.animate().translationY(pos);

v.animate().start();

}

// slide down

slide(yourView, 250, yourViewHeight);

// slide up

slide(yourView, 250, 0);

kerosene answered -03-31T02:41:31Z

1 votes

/**

* Animation that either expands or collapses a view by sliding it down to make

* it visible. Or by sliding it up so it will hide. It will look like it slides

* behind the view above.

*

*/

public class FinalExpandCollapseAnimation extends Animation

{

private View mAnimatedView;

private int mEndHeight;

private int mType;

public final static int COLLAPSE = 1;

public final static int EXPAND = 0;

private LinearLayout.LayoutParams mLayoutParams;

private RelativeLayout.LayoutParams mLayoutParamsRel;

private String layout;

private Context context;

/**

* Initializes expand collapse animation, has two types, collapse (1) and

* expand (0).

*

* @param view

* The view to animate

* @param type

* The type of animation: 0 will expand from gone and 0 size to

* visible and layout size defined in xml. 1 will collapse view

* and set to gone

*/

public FinalExpandCollapseAnimation(View view, int type, int height, String layout, Context context)

{

this.layout = layout;

this.context = context;

mAnimatedView = view;

mEndHeight = mAnimatedView.getMeasuredHeight();

if (layout.equalsIgnoreCase("linear"))

mLayoutParams = ((LinearLayout.LayoutParams) view.getLayoutParams());

else

mLayoutParamsRel = ((RelativeLayout.LayoutParams) view.getLayoutParams());

mType = type;

if (mType == EXPAND)

{

AppConstant.ANIMATED_VIEW_HEIGHT = height;

}

else

{

if (layout.equalsIgnoreCase("linear"))

mLayoutParams.topMargin = 0;

else

mLayoutParamsRel.topMargin = convertPixelsIntoDensityPixels(36);

}

setDuration(600);

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t)

{

super.applyTransformation(interpolatedTime, t);

if (interpolatedTime < 1.0f)

{

if (mType == EXPAND)

{

if (layout.equalsIgnoreCase("linear"))

{

mLayoutParams.height = AppConstant.ANIMATED_VIEW_HEIGHT

+ (-AppConstant.ANIMATED_VIEW_HEIGHT + (int) (AppConstant.ANIMATED_VIEW_HEIGHT * interpolatedTime));

}

else

{

mLayoutParamsRel.height = AppConstant.ANIMATED_VIEW_HEIGHT

+ (-AppConstant.ANIMATED_VIEW_HEIGHT + (int) (AppConstant.ANIMATED_VIEW_HEIGHT * interpolatedTime));

}

mAnimatedView.setVisibility(View.VISIBLE);

}

else

{

if (layout.equalsIgnoreCase("linear"))

mLayoutParams.height = mEndHeight - (int) (mEndHeight * interpolatedTime);

else

mLayoutParamsRel.height = mEndHeight - (int) (mEndHeight * interpolatedTime);

}

mAnimatedView.requestLayout();

}

else

{

if (mType == EXPAND)

{

if (layout.equalsIgnoreCase("linear"))

{

mLayoutParams.height = AppConstant.ANIMATED_VIEW_HEIGHT;

mLayoutParams.topMargin = 0;

}

else

{

mLayoutParamsRel.height = AppConstant.ANIMATED_VIEW_HEIGHT;

mLayoutParamsRel.topMargin = convertPixelsIntoDensityPixels(36);

}

mAnimatedView.setVisibility(View.VISIBLE);

mAnimatedView.requestLayout();

}

else

{

if (layout.equalsIgnoreCase("linear"))

mLayoutParams.height = 0;

else

mLayoutParamsRel.height = 0;

mAnimatedView.setVisibility(View.GONE);

mAnimatedView.requestLayout();

}

}

}

private int convertPixelsIntoDensityPixels(int pixels)

{

DisplayMetrics metrics = context.getResources().getDisplayMetrics();

return (int) metrics.density * pixels;

}

}

可以通过以下方式调用该类

if (findViewById(R.id.ll_specailoffer_show_hide).getVisibility() == View.VISIBLE) {

((ImageView) findViewById(R.id.iv_specialhour_seemore)).setImageResource(R.drawable.white_dropdown_up);

FinalExpandCollapseAnimation finalExpandCollapseAnimation = new FinalExpandCollapseAnimation(

findViewById(R.id.ll_specailoffer_show_hide),

FinalExpandCollapseAnimation.COLLAPSE,

SpecialOfferHeight, "linear", this);

findViewById(R.id.ll_specailoffer_show_hide)

.startAnimation(finalExpandCollapseAnimation);

((View) findViewById(R.id.ll_specailoffer_show_hide).getParent()).invalidate();

} else {

((ImageView) findViewById(R.id.iv_specialhour_seemore)).setImageResource(R.drawable.white_dropdown);

FinalExpandCollapseAnimation finalExpandCollapseAnimation = new FinalExpandCollapseAnimation(

findViewById(R.id.ll_specailoffer_show_hide),

FinalExpandCollapseAnimation.EXPAND,

SpecialOfferHeight, "linear", this);

findViewById(R.id.ll_specailoffer_show_hide)

.startAnimation(finalExpandCollapseAnimation);

((View) findViewById(R.id.ll_specailoffer_show_hide).getParent()).invalidate();

}

Amardeep answered -03-31T02:41:57Z

1 votes

我改编了汤姆埃斯特雷斯当前接受的答案,该答案有效,但动画不稳定且不太流畅。 我的解决方案基本上用collapse( myView );取代了expand( myView );,它可以配备你选择的Interpolator,以实现各种效果,如过冲,反弹,加速等。

此解决方案适用于具有动态高度的视图(即使用expand( myView );),因为它首先测量实际所需的高度,然后设置为该高度的动画。

public static void expand(final View v) {

v.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.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);

ValueAnimator va = ValueAnimator.ofInt(1, targetHeight);

va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

public void onAnimationUpdate(ValueAnimator animation) {

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

v.requestLayout();

}

});

va.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationEnd(Animator animation) {

v.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;

}

@Override public void onAnimationStart(Animator animation) {}

@Override public void onAnimationCancel(Animator animation) {}

@Override public void onAnimationRepeat(Animator animation) {}

});

va.setDuration(300);

va.setInterpolator(new OvershootInterpolator());

va.start();

}

public static void collapse(final View v) {

final int initialHeight = v.getMeasuredHeight();

ValueAnimator va = ValueAnimator.ofInt(initialHeight, 0);

va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

public void onAnimationUpdate(ValueAnimator animation) {

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

v.requestLayout();

}

});

va.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationEnd(Animator animation) {

v.setVisibility(View.GONE);

}

@Override public void onAnimationStart(Animator animation) {}

@Override public void onAnimationCancel(Animator animation) {}

@Override public void onAnimationRepeat(Animator animation) {}

});

va.setDuration(300);

va.setInterpolator(new DecelerateInterpolator());

va.start();

}

然后,您只需致电expand( myView );或collapse( myView );。

Magnus W answered -03-31T02:42:39Z

如果觉得《android 折叠动画 Android:展开/折叠动画》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。