本来以为挺简单的,无非就是监听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);
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);
后续我还会更新有关的动画原理和使用,期待吧