博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android:展开/折叠动画
阅读量:2290 次
发布时间:2019-05-09

本文共 40163 字,大约阅读时间需要 133 分钟。

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

[v1][v2]

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

我尝试过这样的事情:

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的一行! 任何简单的方法来用吗?


#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()    {        @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;        }    };    // Expansion speed of 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;        }    };    // Collapse speed of 1dp/ms    a.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;    }    @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;    }}

#3楼

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


#4楼

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

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

//convert 100dp to pixel valueint 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() {                                                                 @Override                                                                 public void invoke($ d, Object... args) {                                                                     $.toast(context, "finished", Toast.LENGTH_SHORT);                                                                 }                                                             }));

#5楼

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

您将必须为该移位中涉及的所有最顶层布局设置此属性。 如果现在将一种布局的可见性设置为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);    }    @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);

#7楼

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

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

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

#9楼

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

anim_grow.xml

anim_shrink.xml

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

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

#12楼

@Tom Esterez的 ,但已更新为根据正确使用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() {        @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);    }

#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() {        @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的初始代码!


#14楼

使用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();

#15楼

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

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

#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() {        @Override        protected void applyTransformation(float interpolatedTime, Transformation t) {            if (interpolatedTime == 1 && targetHeight == 0) {                view.setVisibility(View.GONE);            }            view.getLayoutParams().height = (int) (initialHeight + distance * interpolatedTime);            view.requestLayout();        }        @Override        public 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());        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();                    }

#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() {            @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 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() {        @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是包含该视图的容器视图。


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

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


#25楼

我改编 ,该方法虽然有效,但动画不连贯且不稳定。 我的解决方案基本上是用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() {        @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 );


#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;    }    @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;    }}

#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 = 0    val 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 = 0    view.visibility = View.VISIBLE    animateView(view, initialHeight, targetHeight)}private fun collapse(view: View) {    val initialHeight = view.measuredHeight    val targetHeight = 0    animateView(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 Int        v.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 = 300    valueAnimator.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;}

}

转载地址:http://mgdnb.baihongyu.com/

你可能感兴趣的文章
MySQL binlog的三种模式
查看>>
MySQL利用binlog增量恢复数据库
查看>>
Tomcat多实例多应用
查看>>
Tomcat启动慢解决方法
查看>>
Tomca主配置文件详解
查看>>
Tomcat创建虚拟主机
查看>>
Tomcat集群
查看>>
Tomcat DeltaManager集群共享session
查看>>
Tomcat连接Apache之mod_proxy模块
查看>>
sersync+rsync数据同步
查看>>
使用com.aspose.words将word模板转为PDF文件时乱码解决方法
查看>>
Linux发送邮件
查看>>
YUM安装PHP5.6
查看>>
YUM源安装MySQL5.7
查看>>
Tomcat日志切割cronolog
查看>>
glibc-2.14安装
查看>>
升级openssl zlib版本 安装nginx
查看>>
ab压力测试
查看>>
SVN指定端口启动
查看>>
网站访问速度一般检查参数
查看>>