原标题:Android阻尼效果 | 自定义进阶之实现MIUI的拖动视差效果
作者:xiaoyanger
来源:/u/25c3b13f87ce
在MIUI上有一些界面在拖动的时候有一个视差效果:
在可以滚动的视图中,内容滚动到顶部时继续下拉,整个视图就有一个竖直方向拉伸的视差效果。滚动到底部继续上拉,也有同样的效果。
滚动视图可能是ScrollView、RecyclerView,要实现这样的效果,需要自定义并拦截Touch事件,重新处理事件逻辑。
以RecyclerView为例,我们自定义一个ParallaxRecyclerView,复写onInterceptTouchEvent方法:
滚动RecyclerView到达顶部或者底部继续拖动时,需要拦截Touch事件。所以在MotionEvent.ACTION_MOVE时需要判断当前RecyclerView是否在顶部或者底部。需要注意的是,当RecyclerView中的item没有填充满整视图时,RecyclerView的状态既是在顶部也是在底部。
mActivePointerId表示在多点触控是当前活动手指的id,mInitialMotionY为手指按下时的Y坐标。
当达到顶部或底部继续拖动时,根据当前的位置(isScrollToTop()、isScrollToBottom())和ACTION_MOVE时的移动距离yDiff来判断是否需要拦截:在顶部时向上拖动并且yDiff>mTouchSlop就需要拦截,底部时向下拖动同样yDiff>mTouchSlop也需要拦截,同时在顶部和底部时满足Math.abs(yDiff)>mTouchSlop也需要拦截。
需要拦截都是在没有被拖动(!isBeingDragged)的情况下。
RecyclerViev既没有在顶部也没有在底部时,说明item滚动到中间,可以上下继续滚动,不需要拦截,交给super.onInterceptTouchEvent(event)来处理。同时其它不需要拦截的情况也都交给super来处理。
onSecondaryPointerUp(event)为当第二个手指离开屏幕是需要重新设置mActivePointerId:
拦截到TouchEvent,在onTouchEven中处理,实现拖动视差效果:
代码虽然有点长,但是逻辑很简单,在拦截到ACTION_MOVE事件后,同样根据顶部或底部位置以及滚动的距离mDistance来确定是否消费掉该事件。不需要消费的直接给`super.onTouchEvent(event)来处理,需要消费的话根据mDistance来计算出缩放的比例mScale,再通过pull(mScale)和push(mScale)来缩放。
在ACTION_UP时,需要将缩放的视图通过动画还原到初始状态。这里也需要判断位置,因为不同位置的的缩放中心点不一样。同时即在顶部也在底部时是根mDistance的正负值来判断拖动的方向。
这样就OK了,如果需要实现ScrollView、ListView、GridView也是一样的逻辑,源码中已经有了ParallaxScrollView的实现,看下最终效果图:
ParallaxRecyclerView:
ParallaxScrollView
源码:
/xiaoyanger0825/Parallax
如果你有想学习的文章直接留言,我会整理征稿。如果你有好的文章想和大家分享欢迎投稿,直接向我投递文章链接即可。
责任编辑: