LinearHorizontalRecyclerView

来源:互联网 发布:口袋妖怪手办淘宝 编辑:程序博客网 时间:2024/05/29 12:00

最近在学习安卓,找点应用模仿一下界面


LinearHorizontalRecyclerView只是RecyclerView + LinearLayout + Horizontal而已

想要达到的效果是这样的先上图:


大家先看番剧更新这一区域,它是由一个RecyclerView + 水平线性管理器 组成的


现在我们向左滑一点点 假设滑动距离是10  此时手不要放开


这样第一个Item就有部分被遮住了, 然后再向右滑动超过10的距离,

就会发现现在变成ViewPager在滑动了 原因是因为 RV(RecyclerView的简称)已经滑到尽头了 所以事件就被扔给了父元素(ViewPager,VP) 而且以后RV再也捕获收到事件了(除非释放又开始)

这样的结果有时候是我们想要的效果 不过有的时候不是我们想要的

我现在想达到的效果是:"如果一开始RV就是在最左边并且你要向右滑,那么我才允许ViewPager捕获事件" 否则的话请先滑动到最左边 然后再次向右滑    然后对于最右边的情况也是一样

这样可以避免 用户滑动距离太大 或 RV里面的项比较少 而直接切换到下一个Page


于是我们需要重写RV


@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN://一开始我们要无条件的请求不要拦截该事件 这样我们才有处理的机会getParent().requestDisallowInterceptTouchEvent(true);mLastX = ev.getX();mLastY = ev.getY();mMoveInited = false;//还没第一次movemParentCanIntercept = false;//父亲不允许拦截我break;case MotionEvent.ACTION_MOVE:float x = ev.getX();float y = ev.getY();if (!mMoveInited) {mMoveInited = true;//标记if (Math.abs(x - mLastX) > Math.abs(y - mLastY)) {//水平移动比较多
<span style="white-space:pre"></span>//判断一下该RV还能不能向左移动boolean canLeft =...
<span style="white-space:pre"></span>//判断一下该RV还能不能向右移动boolean canRight = ...
<span style="white-space:pre"></span>if ((x > mLastX && !canLeft) || (x < mLastX && !canRight)) {//当且仅当我不能向左走而你又要让我向左走(手右滑) 或 相反...getParent().requestDisallowInterceptTouchEvent(false);mParentCanIntercept = true;}} else {//垂直比移动比较多getParent().requestDisallowInterceptTouchEvent(false);mParentCanIntercept = true;}} else {//这里是第二次move及其以后的moveif (mParentCanIntercept)//mParentCanIntercept=true的话只有上面2个来源 都是可以允许父亲拦截我的getParent().requestDisallowInterceptTouchEvent(false);}mLastX = x;mLastY = y;break;}return super.dispatchTouchEvent(ev);}
引入了若干个

mLastX 记录上一次的X, mLastY 记录上一次的Y, mMoveInited 用于是否已经过了第一个ACTION_MOVE,  mParentCanIntercept用于表示是否该让父元素拦截

然后还有两个临时变量 canLeft 用于表示该RV能不能向左移动  canRight:表示该RV能不能向右移动

整体的判断逻辑还是比较简单的

有一个关键是如何获得

canLeft和canRight, 可以使用LinearLayoutManager的findFirstCompletelyVisibleItemPosition()和findLasttCompletelyVisibleItemPosition()方法

canLeft=((LinearLayoutManager)getLayoutManager()).findFirstCompletelyVisibleItemPosition()>0; 如果第一个元素不是完全可见的 那么就还有向左边走的空间
canRight = ((LinearLayoutManager) getLayoutManager()).findLastCompletelyVisibleItemPosition() < getLayoutManager().getItemCount() - 1; 如果最后一个元素不是完全可见的 那么还有向右走的空间
这样就OK了
上面代码还同时解决了一个问题 就是:
当你第一个ACTION_MOVE的时候 如果 做的比较多的是水平的移动 那么你以后只能进行水平移动 如果你做的比较多的是垂直移动 那么你以后只能做垂直移动(其实这个垂直移动很有可能被父元素捕获 从而RV失去事件 不过这一般是我们想要的)
否则会出现一个情况就是:
你左右滑动你的RV, 手不放, 然后变成上下滑动,手不放 这时候你就会丢失你的触摸事件 因为我们的RV是水平的 不允许上下滑动 所以一旦有上下滑动 就会被父元素捕获 从而导致RV失去事件(意思就是: 即使你从上下滑动再变成水平滑动,RV也不会理你了)


0 0
原创粉丝点击