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

Android:展开/折叠动画

时间:2024-02-13 18:21:19

相关推荐

Android:展开/折叠动画

假设我有一个带有以下内容的垂直linearLayout:

[v1][v2]

默认情况下,v1的可见值= GONE。 我想用扩展动画显示v1并同时按下v2。

我尝试过这样的事情:

Animation a = new Animation(){int initialHeight;@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {final int newHeight = (int)(initialHeight * interpolatedTime);v.getLayoutParams().height = newHeight;v.requestLayout();}@Overridepublic void initialize(int width, int height, int parentWidth, int parentHeight) {super.initialize(width, height, parentWidth, parentHeight);initialHeight = height;}@Overridepublic boolean willChangeBounds() {return true;}};

但是有了这个解决方案,动画开始时我眨了眨眼。 我认为这是由v1在应用动画之前显示完整尺寸引起的。

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

#1楼

我看到这个问题开始流行,所以我发布了实际的解决方案。 主要优点是您不必知道扩展的高度即可应用动画,并且一旦视图扩展后,如果内容更改,视图就会适应高度。 这对我很有效。

public static void expand(final View v) {int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(), View.MeasureSpec.EXACTLY);int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);v.measure(matchParentMeasureSpec, wrapContentMeasureSpec);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(){@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {v.getLayoutParams().height = interpolatedTime == 1? LayoutParams.WRAP_CONTENT: (int)(targetHeight * interpolatedTime);v.requestLayout();}@Overridepublic boolean willChangeBounds() {return true;}};// Expansion speed of 1dp/msa.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(){@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {if(interpolatedTime == 1){v.setVisibility(View.GONE);}else{v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);v.requestLayout();}}@Overridepublic boolean willChangeBounds() {return true;}};// Collapse speed of 1dp/msa.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));v.startAnimation(a);}

如@Jefferson在评论中所提到的,您可以通过更改动画的持续时间(并因此更改速度)来获得更平滑的动画。 目前,它的设置速度为1dp / ms

#2楼

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

public class WidthExpandAnimation extends Animation{int _targetWidth;View _view;public WidthExpandAnimation(View view){_view = view;}@Overrideprotected 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();}@Overridepublic void initialize(int width, int height, int parentWidth, int parentHeight){super.initialize(width, height, parentWidth, parentHeight);_targetWidth = width;}@Overridepublic boolean willChangeBounds() {return true;}}

#3楼

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

#4楼

使用droidQuery确实很简单。 首先,请考虑以下布局:

<LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical" ><LinearLayoutandroid:id="@+id/v1"android:layout_width="wrap_content"android:layout_height="wrap_content" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content" android:text="View 1" /></LinearLayout><LinearLayoutandroid:id="@+id/v2"android:layout_width="wrap_content"android:layout_height="0dp" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content" android:text="View 2" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content" android:text="View 3" /></LinearLayout></LinearLayout>

我们可以使用以下代码将高度设置为所需的高度,例如100dp

//convert 100dp to pixel valueint height = (int) TypedValue.applyDimension(PLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());

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

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

为了使动画更具吸引力,请考虑添加缓动效果:

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

您也可以使用duration()方法更改AnimationOptionsduration(),或处理动画结束时发生的情况。 对于一个复杂的示例,请尝试:

$.animate("{ height: " + height + "}", new AnimationOptions().easing($.Easing.BOUNCE).duration(1000).complete(new Function() {@Overridepublic void invoke($ d, Object... args) {$.toast(context, "finished", Toast.LENGTH_SHORT);}}));

#5楼

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

<LinearLayout android:id="@+id/container"android:animateLayoutChanges="true".../>

您将必须为该移位中涉及的所有最顶层布局设置此属性。如果现在将一种布局的可见性设置为GONE,则另一种布局将占用该空间,因为消失的一种布局正在释放它。 将有一个默认的动画,某种程度上是“淡出”的,但是我认为您可以更改此动画-但到目前为止,我还没有测试过最后一个动画。

#6楼

如果您不想一直扩展或折叠-这是一个简单的HeightAnimation-

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);}@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {view.getLayoutParams().height = (int) (originalHeight + perValue * interpolatedTime);view.requestLayout();}@Overridepublic boolean willChangeBounds() {return true;}}

用法:

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

#7楼

对于平滑动画,请使用带有运行方法的处理程序.....并享受扩展/折叠动画

class AnimUtils{public void expand(final View v) {int ANIMATION_DURATION=500;//in milisecondv.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);final int targtetHeight = v.getMeasuredHeight();v.getLayoutParams().height = 0;v.setVisibility(View.VISIBLE);Animation a = new Animation(){@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {v.getLayoutParams().height = interpolatedTime == 1? LayoutParams.WRAP_CONTENT: (int)(targtetHeight * interpolatedTime);v.requestLayout();}@Overridepublic boolean willChangeBounds() {return true;}};// 1dp/msa.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(){@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {if(interpolatedTime == 1){v.setVisibility(View.GONE);}else{v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);v.requestLayout();}}@Overridepublic boolean willChangeBounds() {return true;}};// 1dp/msa.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 animationnew Handler().postDelayed(new Runnable() {@Overridepublic void run() {new AnimationUtililty().expand(inactive);}}, 1000);//For collapsenew Handler().postDelayed(new Runnable() {@Overridepublic 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() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic 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);}

#8楼

我创建了不需要指定布局高度的版本,因此它使用起来更容易,更清洁。 解决方案是在动画的第一帧中获取高度(当时至少在我的测试中可用)。 这样,您可以为视图提供任意高度和底边距。

构造函数中还有一个小技巧-底部边距设置为-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);}@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {super.applyTransformation(interpolatedTime, t);//view height is already known when the animation startsif(interpolatedTime==0){mMarginStart = -mAnimatedView.getHeight();}mViewLayoutParams.bottomMargin = (int)((mMarginEnd-mMarginStart) * interpolatedTime)+mMarginStart;mAnimatedView.setLayoutParams(mViewLayoutParams);}}

#9楼

这是我的解决方案,我的ImageView100%增长到200%并使用res/anim/文件夹中的两个动画文件恢复到其原始大小

anim_grow.xml

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="/apk/res/android"android:interpolator="@android:anim/accelerate_interpolator"><scaleandroid: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" /></set>

anim_shrink.xml

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="/apk/res/android"android:interpolator="@android:anim/accelerate_interpolator"><scaleandroid: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" /></set>

ImageView发送到我的方法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() { @Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {imgV.startAnimation(animationShrink);}});animationShrink.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {imgV.startAnimation(animationEnlarge);}});}

#10楼

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

#11楼

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() {@Overridepublic 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() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {v.getLayoutParams().height = (int) animation.getAnimatedValue();v.requestLayout();}});valueAnimator.setInterpolator(new DecelerateInterpolator());valueAnimator.setDuration(duration);valueAnimator.start();}

#12楼

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

// /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() {@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {view.getLayoutParams().height = interpolatedTime == 1? ViewGroup.LayoutParams.WRAP_CONTENT: (int) (targetHeight * interpolatedTime);view.requestLayout();}@Overridepublic 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() {@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {if (interpolatedTime == 1) {view.setVisibility(View.GONE);} else {view.getLayoutParams().height = initialHeight - (int) (initialHeight * interpolatedTime);view.requestLayout();}}@Overridepublic 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 * multiplierreturn (int) (view.getMeasuredHeight() / view.getContext().getResources().getDisplayMetrics().density);}

#13楼

我采用了@LenaYan的解决方案 ,该解决方案对我而言无法正常工作(因为它在折叠和/或扩展之前将View转换为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() {@Overridepublic 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() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {v.getLayoutParams().height = (int) animation.getAnimatedValue();v.requestLayout();}});valueAnimator.setInterpolator(new DecelerateInterpolator());valueAnimator.setDuration(duration);valueAnimator.start();}

用法:

//Expanding the Viewexpand(yourView, 2000, 200);// Collapsing the Viewcollapse(yourView, 2000, 100);

很简单!

感谢LenaYan的初始代码!

#14楼

使用ValueAnimator:

ValueAnimator expandAnimation = ValueAnimator.ofInt(mainView.getHeight(), 400);expandAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(final ValueAnimator animation) {int height = (Integer) animation.getAnimatedValue();RelativeLayout.LayoutParams lp = (LayoutParams) mainView.getLayoutParams();lp.height = height;}});expandAnimation.setDuration(500);expandAnimation.start();

#15楼

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

@Overridepublic 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();}

#16楼

您可以稍微扭转一下使用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())

#17楼

基于@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;view.setVisibility(View.VISIBLE);Animation a = new Animation() {@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {if (interpolatedTime == 1 && targetHeight == 0) {view.setVisibility(View.GONE);}view.getLayoutParams().height = (int) (initialHeight + distance * interpolatedTime);view.requestLayout();}@Overridepublic boolean willChangeBounds() {return true;}};a.setDuration(duration);view.startAnimation(a);}

#18楼

public static void slide(View v, int speed, int pos) {v.animate().setDuration(speed);v.animate().translationY(pos);v.animate().start();}// slide downslide(yourView, 250, yourViewHeight);// slide upslide(yourView, 250, 0);

#19楼

/*** 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());elsemLayoutParamsRel = ((RelativeLayout.LayoutParams) view.getLayoutParams());mType = type;if (mType == EXPAND){AppConstant.ANIMATED_VIEW_HEIGHT = height;}else{if (layout.equalsIgnoreCase("linear"))mLayoutParams.topMargin = 0;elsemLayoutParamsRel.topMargin = convertPixelsIntoDensityPixels(36);}setDuration(600);}@Overrideprotected 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);elsemLayoutParamsRel.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;elsemLayoutParamsRel.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();}

#20楼

除了汤姆·埃斯特雷斯(Tom Esterez)的出色回答和埃里克·B(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);}

#21楼

@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() {@Overridepublic 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() {@Overridepublic 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 usageexpandOrCollapseView((Your ViewGroup),(Your ViewGroup).getVisibility()!=View.VISIBLE);

#22楼

这是一个正确的工作解决方案,我已经对其进行了测试:

说明:

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() {@Overridepublic void onAnimationStart(Animator animator) {}@Overridepublic void onAnimationEnd(Animator animator) {//Height=0, but it set visibility to GONEllDescp.setVisibility(View.GONE);}@Overridepublic void onAnimationCancel(Animator animator) {}@Overridepublic void onAnimationRepeat(Animator animator) {}});mAnimator.start();}

价值动画师:

private ValueAnimator slideAnimator(int start, int end) {ValueAnimator mAnimator = ValueAnimator.ofInt(start, end);mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {//Update Heightint value = (Integer) valueAnimator.getAnimatedValue();ViewGroup.LayoutParams layoutParams = llDescp.getLayoutParams();layoutParams.height = value;v.setLayoutParams(layoutParams);}});return mAnimator;}

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

#23楼

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

#24楼

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

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(){@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {final int newHeight = (int)(initialHeight * interpolatedTime);v.getLayoutParams().height = newHeight;v.requestLayout();}@Overridepublic boolean willChangeBounds() {return true;}};a.setDuration(5000);v.startAnimation(a);return a;}

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

#25楼

我改编了汤姆·埃斯特雷斯(Tom Esterez)当前接受的答案 ,该方法虽然有效,但动画不连贯且不稳定。 我的解决方案基本上是用ValueAnimator代替Animation,后者可以与您选择的Interpolator配合使用,以实现各种效果,例如超调,反弹,加速等。

该解决方案非常适合具有动态高度的视图(即使用WRAP_CONTENT),因为它首先测量实际所需的高度,然后将其设置为动画高度。

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() {@Overridepublic 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() {@Overridepublic 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 );

#26楼

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

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;}@Overrideprotected 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();}@Overridepublic void initialize(int width, int height, int parentWidth,int parentHeight) {super.initialize(width, height, parentWidth, parentHeight);}@Overridepublic boolean willChangeBounds() {return true;}}

#27楼

利用Kotlin扩展功能,这是经过测试的最短答案

只需在任何视图上调用animateVisibility(expand / collapse)。

fun View.animateVisibility(setVisible: Boolean) {if (setVisible) expand(this) else collapse(this)}private fun expand(view: View) {view.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)val initialHeight = 0val targetHeight = view.measuredHeight// Older versions of Android (pre API 21) cancel animations for views with a height of 0.//v.getLayoutParams().height = 1;view.layoutParams.height = 0view.visibility = View.VISIBLEanimateView(view, initialHeight, targetHeight)}private fun collapse(view: View) {val initialHeight = view.measuredHeightval targetHeight = 0animateView(view, initialHeight, targetHeight)}private fun animateView(v: View, initialHeight: Int, targetHeight: Int) {val valueAnimator = ValueAnimator.ofInt(initialHeight, targetHeight)valueAnimator.addUpdateListener { animation ->v.layoutParams.height = animation.animatedValue as Intv.requestLayout()}valueAnimator.addListener(object : Animator.AnimatorListener {override fun onAnimationEnd(animation: Animator) {v.layoutParams.height = targetHeight}override fun onAnimationStart(animation: Animator) {}override fun onAnimationCancel(animation: Animator) {}override fun onAnimationRepeat(animation: Animator) {}})valueAnimator.duration = 300valueAnimator.interpolator = DecelerateInterpolator()valueAnimator.start()}

#28楼

是的,我同意以上意见。 实际上,似乎正确(或至少最简单的方法)是(在XML中)将初始布局高度指定为“ 0px”-然后您可以为“ toHeight”传递另一个参数(您的自定义Animation子类的构造函数的“最终高度”),例如在上面的示例中,它看起来像这样:

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

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

#29楼

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

contentView.measure(DUMMY_HIGH_DIMENSION, DUMMY_HIGH_DIMENSION);int finalHeight = view.getMeasuredHeight();

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

#30楼

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

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

和崩溃:

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

#31楼

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

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

希望对您有所帮助。

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;}@Overrideprotected 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();}@Overridepublic void initialize(int width, int height, int parentWidth, int parentHeight) {super.initialize(width, height, parentWidth, parentHeight);}@Overridepublic boolean willChangeBounds() {return true;}

}

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

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