Andorid的好东西Android开发Android填坑记录

关于view的visible和gone动画的坑

2016-06-13  本文已影响6652人  肉团先生

title: "关于view的visible和gone动画的坑"
date: 2016-05-31 00:38:33
categories: android
tags:[android,Animator]


需求:如图所示,我需要做一个View的显示和消失的动画。看似简单,但是坑还是不少。消失的动画很简单,难点在visible的动画。因为动画是发生在visible之后,所以导致会生硬的将其他的view移到右边,然后在进行动画.

从传统动画到属性动画,各种尝试,结果失败告终。

跟同事讨论下,他的建议是:visible快速的一个动画左移,然后再一个动画缓慢的右移回来。实践下效果能够缓慢出来,但是view会一闪而过,体验十分不好。

按着这个思路,我们可以移动其他的view,通过遮住这个checkbox,来达到效果,那么只需要改变布局即可。

效果: enter image description here
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/bg_white"
    android:minHeight="@dimen/dp_90">
    <CheckBox
        android:id="@+id/cb_select"
        android:layout_width="@dimen/dp_36"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="@dimen/dp_12"
        android:button="@null"
        android:checked="@{data.isSelected}"
        android:drawableLeft="@drawable/selector_checkbox_red"
        android:maxHeight="@dimen/dp_90"
        android:onClick="@{data.onClick()}"
        bind:visibility="@{data.isEditMode}" />
    <LinearLayout
        bind:move="@{data.isEditMode}"
        android:layout_centerVertical="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/dp_9">

        <ImageView
            android:id="@+id/iv_goods_pic"
            android:layout_width="@dimen/dp_61"
            android:layout_height="@dimen/dp_61"
            android:layout_centerVertical="true"
            android:layout_gravity="center_vertical"
            android:background="@drawable/shape_imageview_bg"
            android:src="@{data.img}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/dp_13"
            android:layout_marginTop="@dimen/dp_21"
            android:layout_weight="1"
            android:text="@{data.name}"
            android:textColor="@color/black_43"
            android:textSize="@dimen/font_11" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:layout_marginBottom="@dimen/dp_12"
            android:layout_marginTop="@dimen/dp_14"
            android:text="@{XmlUtil.formatPrice(data.skuPrice)}"
            android:textColor="@color/font_red_41"
            android:textSize="@dimen/font_11" />
    </LinearLayout>
</RelativeLayout>

对应的绑定代码:

@BindingAdapter("bind:visibility")
public static void showVisibility(final View view, boolean visible) {
    if (view.getTag() == null) {
        view.setTag(true);
    }
    if (visible) {
        view.animate().alpha(1);
    } else {
        view.animate().alpha(0);
    }
}
@BindingAdapter("bind:move")
public static void animMove(final ViewGroup viewGroup, boolean visible) {
    if (viewGroup.getTag() == null) {
        viewGroup.setTag(true);
    }
    if (visible) {
        viewGroup.animate().translationX(Systems.dpToPx(viewGroup.getContext(), 36));
    } else {
        viewGroup.animate().translationX(0);
    }
}


另一种实现方式思路--通过改变高度达到要求

通过改变将要显示view的高度/宽度来达到要求。即:宽度/高度 从0开始逐步变成指定的高度。因为visible的时候,高度为0所以看不到一闪而过的情况。
来源:android群英传

效果图:


下面提供关键代码:

private void animOpen(final  View view){
    view.setVisibility(View.VISIBLE);
    ValueAnimator va = createDropAnim(view,0,mHiddenViewMeasuredHeight);
    va.start();
}

private void animClose(final  View view){
    int origHeight = view.getHeight();
    ValueAnimator va = createDropAnim(view,origHeight,0);
    va.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            view.setVisibility(View.GONE);
        }
    });
    va.start();
}

/**
 * 使用动画的方式来改变高度解决visible不一闪而过出现
 * @param view
 * @param start 初始状态值
 * @param end 结束状态值
 * @return
 */
private ValueAnimator createDropAnim(final  View view,int start,int end) {
    ValueAnimator va = ValueAnimator.ofInt(start, end);
    va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int value = (int) animation.getAnimatedValue();//根据时间因子的变化系数进行设置高度
            ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
            layoutParams.height = value;
            view.setLayoutParams(layoutParams);//设置高度
        }
    });
    return  va;
}

这种方式的缺点很明显:只能从上而下出现,为什么?

因为android的view默认的坐标系是左上角,也就意味着高度只能从上而下扩展。

当遇到从下而上出现则束手无策。开发还真的遇到这样的需求。但有之前的经验+转场动画setAlpha的思路,想到以下方式:

效果图:

实现代码:

binding.btnShow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//bottom layout的出现于消失
if(isFirst){
    binding.llLayoutBottom.setAlpha(0);
    binding.llLayoutBottom.setVisibility(View.VISIBLE);
}
Tasks.handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        if(isEdit&&isFirst){
            logger.e("bottom="+binding.llLayoutBottom.getBottom());
            binding.llLayoutBottom.animate()
            .y(binding.llLayoutBottom.getBottom())
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    if(isFirst){
                        binding.llLayoutBottom.setAlpha(1);
                        logger.e("getTop="+binding.llLayoutBottom.getTop());
                        binding.llLayoutBottom.animate().y(binding.llLayoutBottom.getTop()).setDuration(1000);
                        isFirst=false;
                    }
                }
            })
            .setDuration(1);
        }else if(isEdit){//非第一次的情况执行
            logger.e("getTop="+binding.llLayoutBottom.getTop());
            binding.llLayoutBottom.animate()
            .y(binding.llLayoutBottom.getTop()).setDuration(1000);    
        }
        else  {
            logger.e("getBottom="+binding.llLayoutBottom.getBottom()+"getHeight"+binding.llLayoutBottom.getHeight());
            binding.llLayoutBottom.animate()
            .y(binding.llLayoutBottom.getBottom()).setDuration(1000);
        }

    }
}, 500);

}
});

上述代码总结:

  1. 为了偷懒直接使用animate()方法,却忘记了一旦进行监听AnimatorListener后,只要每执行一次动画,对应的方法就会执行一次,导致在打log中onAnimationEnd一直执行,迫使之前实现的效果一直都不正确。动画总是移动回来再移动回去。
  1. 关于坐标系的问题,发现使用屏幕的高度-llLayoutBottom.getHeight()不靠谱,对应的view只出现一半。暂时不明,所以直接使用getBottom、getTop来设置。可以发现动画的移动并没有其真实的坐标:getBottom、getTop来时原来的
  2. log+debug会加快调试的时间
上一篇 下一篇

猜你喜欢

热点阅读