Android 仿京东,淘宝RecyclerView嵌套ViewPager嵌套RecyclerView商品展示 | 您所在的位置:网站首页 › viewpager嵌套recyclerview › Android 仿京东,淘宝RecyclerView嵌套ViewPager嵌套RecyclerView商品展示 |
最近看到京东,淘宝都有RecyclerView嵌套ViewPager嵌套RecyclerView商品展示的效果,效果挺好,废话不多说先看效果图:
技能点: 1.Android事件分发机制等 需求点: 1.列表嵌套,内层的列表可以左右切换 2.ViewPager可以点击和滑动切换 最近在淘宝京东看到类似的效果,有时间就写了一下,效果实现了,但是感觉解决问题的思路和代码有很多瑕疵,写出来抛砖引玉,希望大佬们不吝赐教,写的不好不喜勿喷! 下面进入正题,先看下布局结构:.那先说下淘宝和京东采取的方式: 淘宝和京东部分页面切换ViewPager时候重新拉取数据(可能没有重新拉数据,只是notify了一下)将RecyclerView直接展示到初始状态 京东的部分界面(京东->我的->下拉->为你推荐)处理方式为:当Tab为非吸顶状态时候切换ViewPager,外层RecyclerView滑动到Tab吸顶 demo因为用的是假数据,所以没做处理,但是代码中有在tab非吸顶状态时候,外层RecyclerView优先处理滑动事件的代码 个人感觉第一种处理方式比较好一点,demo的代码如下(需要请自行修改,PagerFragment.java) if(! ((MainActivity)getActivity()).isStick){ ((MainActivity)getActivity()).adjustScroll(true); return false; } 下面说下实现方式,以及问题的解决(布局等细节就不贴出来了,详情见demo): 外部的RecyclerView为自定义的View继承自RecyclerView重写onInterceptTouchEvent方法 处理滑动事件: private float downX ; //按下时 的X坐标 private float downY ; //按下时 的Y坐标 @Override public boolean onInterceptTouchEvent(MotionEvent e) { float x= e.getX(); float y = e.getY(); switch (e.getAction()){ case MotionEvent.ACTION_DOWN: //将按下时的坐标存储 downX = x; downY = y; break; case MotionEvent.ACTION_MOVE: //获取到距离差 float dx= x-downX; float dy = y-downY; //通过距离差判断方向 int orientation = getOrientation(dx, dy); switch (orientation) { //左右滑动交给ViewPager处理 case 'r': setNeedIntercept(false); break; //左右滑动交给ViewPager处理 case 'l': setNeedIntercept(false); break; } return isNeedIntercept; } return super.onInterceptTouchEvent(e); } public void setNeedIntercept(boolean needIntercept) { isNeedIntercept = needIntercept; } private int getOrientation(float dx, float dy) { if (Math.abs(dx)>Math.abs(dy)){ //X轴移动 return dx>0?'r':'l';//右,左 }else{ //Y轴移动 return dy>0?'b':'t';//下//上 } }isNeedIntercept为是否拦截滑动事件,自己处理.并提供了一个setNeedIntercept方法供外部调用.代码可以看出,横向的滑动直接放行,让ViewPager处理,向上滑动时候如果tab吸顶了且已经滑动到底部,交给内部的RecyclerView处理,否则自己处理. 我们对内层的RecyclerView进行处理,重写其onTouchEvent方法 @Override public boolean onTouchEvent(MotionEvent e) { float x= e.getX(); float y = e.getY(); switch (e.getAction()){ case MotionEvent.ACTION_DOWN: //将按下时的坐标存储 downX = x; downY = y; getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: //获取到距离差 float dx= x-downX; float dy = y-downY; //通过距离差判断方向 int orientation = getOrientation(dx, dy); int[] location={0,0}; getLocationOnScreen(location); switch (orientation) { case 'b': //内层RecyclerView下拉到最顶部时候不再处理事件 if(!canScrollVertically(-1)){ getParent().requestDisallowInterceptTouchEvent(false); if(needIntercepectListener!=null){ needIntercepectListener.needIntercepect(false); } }else{ getParent().requestDisallowInterceptTouchEvent(true); if(needIntercepectListener!=null){ needIntercepectListener.needIntercepect(true); } } break; case 't': if(location[1]Math.abs(dy)){ //X轴移动 return dx>0?'r':'l';//右,左 }else{ //Y轴移动 return dy>0?'b':'t';//下//上 } } public void setMaxY(int height) { this.maxY=height; } public interface NeedIntercepectListener{ void needIntercepect(boolean needIntercepect); } public void setNeedIntercepectListener(NeedIntercepectListener needIntercepectListener) { this.needIntercepectListener = needIntercepectListener; }其中的回调是为了告诉外层的RecyclerView需不需要拦截事件. 滑动冲突到这里基本上处理完了,下面说下吸顶的问题,其实只是思路的问题,这里采取的方式是将TabLayout和ViewPager当做一个外层RecyclerView的最后一个item,并且高度为屏幕高度-状态栏高度,这样当外层RecyclerView滑动到底部,Tab看上去是吸顶的. 简单说下:这个demo之前是按真正的吸顶做的,所以文章改动过,哪里说得不清楚的请直接看demo,主要是处理滑动事件冲突,难度不大,纯属抛砖引玉. 最后暴露一个问题,在外层RecyclerView滑动到底部时,需要将触摸事件交给内层的RecyclerView处理时,按照Demo里的处理方式,手指抬起之后重新滑动,内层RecyclerView才能拿到事件,原因是Demo判断外层RecyclerView是否滑动到底部的代码写在onInterceptTouchEvent里面,这个方法并不会实时调用,试过将判断写在onTouchEvent里面,实时判断再调用onInterceptTouchEvent,但是好像因为内层的RecyclerView并没有消费掉事件,所以这么做并没有效果,并没有实时的将触摸事件交给内层RecyclerView处理,这里尝试了很多方式,都不太理想,希望有思路的大佬给指点一下,效果如下:项目地址:Github |
今日新闻 |
推荐新闻 |
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 |