假设我有一个带有以下内容的垂直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 value
int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_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="http://schemas.android.com/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="http://schemas.android.com/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() 返回错误的值!

    // 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);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 View     collapse(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 down
slide(yourView, 250, yourViewHeight);
// slide up
slide(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 usage
expandOrCollapseView((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;
}@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;
}

}

Android:展开/折叠动画相关推荐

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

    Android:展开/折叠动画 假设我有一个垂直linearLayout: [v1] [v2] 默认情况下,v1具有visibily = GONE. 我想用扩展动画展示v1并同时向下推v2. 我试过这 ...

  2. js 展开折叠动画原理,jquery的toggle切换效果

    效果图: 想法: jquery的展开折叠动画效果很好看,想自己实现一个,结果发现仅仅只靠css添加类和动画是不行,最开始的思路是折叠时候设置高度为0,展开时设置高度设置为auto,让他自己撑开,可是t ...

  3. Android自动伸展动画,android – 如何实现平滑的展开/折叠动画

    我指的是在这里找到的扩展/折叠动画代码. 虽然这样做不好,动画不顺利. 我做一些登录代码. public static void expand(final View v) { v.measure(Me ...

  4. Android 展开/收回动画效果思路与实现

    要实现什么效果? 我们就是要实现如图所示的动画效果,在开始之前我们先了解一下实现这个动画的相关知识. 属性动画相关知识 动画执行的逻辑 逻辑大概流程如下: 为 ValueAnimator 设置动画的时 ...

  5. Android自动伸展动画,Android:展开/折叠动画

    我看到这个问题很受欢迎,所以我贴出了我的实际解决方案.主要的优点是您不需要知道扩展的高度才能应用动画,并且一旦视图被展开,如果内容发生变化,它就会适应高度.对我来说很管用.public static  ...

  6. android 收起下拉菜单,Android 展开/折叠 系统下拉通知栏

    最近几天碰到一个郁闷的问题,在有些机型上面使用PendingIntent.getActivity(context, 0, intent, 0)的方式打开一个指定的Activity后,通知栏并不主动折叠 ...

  7. WPF实现圆形菜单动态展开折叠效果

    实现效果如下: 思路:根据子菜单个数计算旋转角度动态生成子菜单,并设置展开折叠动画. 步骤: 1.自定义按钮MyButton,建立展示图像属性DisplayImage public class MyB ...

  8. android 菜单展开动画,FloatingActionButton实现 展开/折叠 的多级悬浮菜单

    虽然类似这样效果的库网上现在已经有一大堆了,甚至写的比较完美那我为什么还是要去实现呢?理由也很简单:只有自己尝试着去实现才能体会其中的奥妙 ,才能学习到新的知识这样当你在遇到自己陌生的东西就能从容的解 ...

  9. 【jQuery笔记Part2】02-jQuery展开收起动画帷幔效果案例下拉菜单案例显示隐藏更多案例折叠菜单案例

    展开&收起动画&案例 HTML DOM overflow 属性 展开 slideDown(毫秒, 完成回调函数) 收起 slideUp(毫秒, 完成回调函数) 切换 slideTogg ...

最新文章

  1. GNN教程:DGL框架实现GCN算法!
  2. 根据字符出现频率排序
  3. mysql不能改路径到d盘_Windows Server 2008 R2修改MySQL 5.5数据库目录为D盘示例
  4. 测试Linux网卡是否正常工作
  5. linux设备和驱动加载的先后顺序
  6. 本科985末端去哪学计算机好,4所“985高校”,录取分较低,常被拿来捡漏!
  7. 字体大宝库:26款新鲜出炉的高品质免费英文字体
  8. 基础10 多进程、协程(multiprocessing、greenlet、gevent、gevent.monkey、select、selector)...
  9. catia v5法矢数据软件_catia介绍
  10. WPF里面的常用笔刷
  11. 西门子主程序调用子程序_S7200Smart 子程序局部变量使用教程
  12. 职场新人的入门法则:少想、多做、立即执行!
  13. 失败创业者的告白:初创团队应有一位绝对领导者
  14. Linq to sql 结合Entity Framework 的连接查询总结
  15. stm32正交编码器 原理图_ROS机器人平台STM32底层控制部分
  16. 基础总结篇之八:创建及调用自己的ContentProvider
  17. “U盘杀手”出现新变种 提醒用户小心谨防
  18. 七月算法机器学习 11 决策树、随机森林、 adaboost
  19. 手机个人热点连接台式计算机,电脑怎么连接手机个人热点
  20. 一种简单的仓储系统实物可视化分布实现方案

热门文章

  1. android Binary XML file line #1: Binary XML file line #1: Error inflating class x 问题详解
  2. Android Studio自定义模板代码
  3. 传输层端口号的范围是多少?被分为哪两部分_Cu2ZnSnS4纳米晶做空穴传输层经配体改性将低温可喷涂碳电极基钙钛矿太阳能电池的性能提高到17.71...
  4. golang中字符串内置函数整理
  5. Python Tornado搭建高并发Restful API接口服务
  6. bzoj 1233 or 3549
  7. Go语言构建json和解析json实例
  8. 汇总下几个IP计算/转换的shell小脚本-转
  9. invoke与call
  10. HttpURLConnection post请求 数据接收