RecyclerView上下滑动底部控件动画隐藏和显示

本来以为挺简单的,无非就是监听scroll的事件,根据onScrolled的回调去判断上下滑动的方向,然后在此处设置动画的显示和隐藏,结果还是有很多细节需要去处理的. 同时文章后面给出了在资源文件中属性动画,View动画及帧动画的调用代码

以下是部分代码:

mAnimEnter = AnimationUtils.loadAnimation(this, R.anim.pickerview_slide_in_bottom);
mAnimExit = AnimationUtils.loadAnimation(this, R.anim.pickerview_slide_out_bottom);
//设置状态栏变色
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        handlerRecyclerViewScrollStatus(recyclerView, dx, dy);
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
    }
});

此处我用的是View动画,定义的xml资源文件:

 view_slide_in_bottom.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">

  <translate
      android:duration="@integer/animation_default_duration"
      android:fromXDelta="0%"
      android:toXDelta="0%"
      android:fromYDelta="200%"
      android:toYDelta="0%"/>
</set>

view_slide_out_bottom.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">

  <translate
      android:duration="@integer/animation_default_duration"
      android:fromXDelta="0%"
      android:toXDelta="0%"
      android:fromYDelta="0%"
      android:toYDelta="200%"/>
</set>

需要注意的是toYDelta设置成100%一般是不满足的,因为Button需要设置padding和margin值的.


然后是具体实现的代码,其实也很简单:

private void handlerRecyclerViewScrollStatus(RecyclerView recyclerView, int dx, int dy) {

    if (dy > 0 && nViewTitleBg.getAlpha() >= 1.0f) { //此处还包括标题栏的颜色渐变效果

        if (recyclerView.getScrollState() == ScrollState.SCROLL_STATE_SETTLING) { //设置此处的目的的为了防止拖拽中的抖动
            setCommitEvaluateBtAnimExit();
        }

    } else {

        if (recyclerView.getScrollState() == ScrollState.SCROLL_STATE_SETTLING) {//设置此处的目的的为了防止拖拽中的抖动

            setCommitEvaluateBtAnimEnter();
        }

        int scrollY = getScollYDistance() - 60;//根据滑动距离去计算透明度
        float alpha = scrollY * 1.0f / 500;

        nViewTitleBg.setAlpha(alpha); //设置标题栏文字的透明度,产生渐变效果
        if (nStatusBarLine != null) {
            nStatusBarLine.setAlpha(alpha);//设置标题栏背景的透明度,产生渐变效果
        }

    }
    Timber.tag("anim11");
    Timber.e("dy=" + dy + ",     getScollYDistance()=" + getScollYDistance() + ",...ScrollState" + recyclerView.getScrollState());
}

关于这里的判断是必须的,不然手指一直拖拽的话,动画会不停的一直重复执行,一些app 没有处理这里.当然这样的处理也是有问题的,因为除非用户1秒内不停的小动作滑动,底部的控件无法显示,但是在实际环境中是很少存在的.

如果不去设置的话,会导致,1秒内小范围滑动,动画会多次重复启动.

recyclerView.getScrollState() == ScrollState.SCROLL_STATE_SETTLING


然后是动画的代码:

private void setCommitEvaluateBtAnimExit() {
    if (mCommitEvaluateBt.getVisibility() == View.GONE) { //防止重复执行
        return;
    }

    mAnimExit.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            mCommitEvaluateBt.setVisibility(View.GONE); //执行以后,就隐藏,如果滑动的距离不够的话,会导致无法隐藏掉控件,所以这里手动设置
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    });
    mCommitEvaluateBt.startAnimation(mAnimExit);
}

private void setCommitEvaluateBtAnimEnter() {
    if (mCommitEvaluateBt.getVisibility() == View.VISIBLE) {
        return;
    }

    mAnimEnter.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            mCommitEvaluateBt.setVisibility(View.VISIBLE);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });
    mCommitEvaluateBt.startAnimation(mAnimEnter);
}

以上可以用属性动画去设置,遇到的坑应该会更少,因为属性动画是真实的将控件的内容给平移到指定位置了


最后别忘记释放资源,看情况是在onPause还是onDestroy里面去释放.最好即时释放,因为android系统执行释放的时机一般比较晚.

@Override
protected void onDestroy() {
    super.onDestroy();

  
    if (mAnimEnter != null) {
        mAnimEnter.cancel();
        mAnimEnter = null;
    }

    if (mAnimExit != null) {
        mAnimExit.cancel();
        mAnimExit = null;
    }


资源文件动画的调用

属性动画
AnimatorSet set = ( AnimatorSet ) AnimatorInflater .loadAnimator(myContext,
    R.anim.property_animator);
set .setTarget(myObject);
set .start();

View动画
ImageView image = ( ImageView ) findViewById(R.id.image);
Animation hyperspaceJump = AnimationUtils . loadAnimation ( this , R.anim.hyperspace_jump);
image. startAnimation (hyperspaceJump);

XML file saved at   res/drawable/rocket.xml :
<?xml version= "1.0" encoding= "utf-8" ?>
<animation-list xmlns:android = "http://schemas.android.com/apk/res/android"
    android:oneshot = "false" >
    <item android:drawable = "@drawable/rocket_thrust1" android:duration = "200" />
    <item android:drawable = "@drawable/rocket_thrust2" android:duration = "200" />
    <item android:drawable = "@drawable/rocket_thrust3" android:duration = "200" />
</animation-list>
This application code will set the animation as the background for a View, then play the animation:
ImageView rocketImage = ( ImageView ) findViewById(R.id.rocket_image);
rocketImage. setBackgroundResource (R.drawable.rocket_thrust);

rocketAnimation = ( AnimationDrawable ) rocketImage. getBackground() ;
rocketAnimation. start() ;


后续我还会更新有关的动画原理和使用,期待吧

此处是动画的文档: https://developer.android.google.cn/guide/

猜你喜欢

转载自blog.csdn.net/yang1349day/article/details/80355557