RecyclerView实现双列表联动

版权声明:允许转载,只要标注转载地址即可 https://blog.csdn.net/z979451341/article/details/81223133

项目地址

本次是通过RecyclerView实现两个列表:主列表、详情列表。通过点击主列表某个item,详情列表通过自动移动显示相应的item,并使其置顶,通过滑动详情列表,主列表也会自动移动到相应的位置。

上效果图

 

一.预备知识

获取当前RecyclerView可见的第一个和最后的item在整体列表里的顺序

            layoutM.findFirstVisibleItemPosition()
            layoutM.findLastVisibleItemPosition()

还有第一个完全可见的item和最后一个完全可见的item

            layoutM.findFirstCompletelyVisibleItemPosition()
            layoutM.findLastCompletelyVisibleItemPosition()

还有移动到某个item的函数,这是个大坑,因为他只管滑动直到该item完全显示,所以调用这个函数有三种情况

(1)当目标item的在当前第一个完全可见item的上面时,调用这个函数使该item置顶

(2)当目标item处于第一个完全可见的item和最后一个完全可见的item之间时,调用函数没反应,因为他是完全显示的,所以他就不管了

(3)当目标item在当前最后一个完全可见的item的下面时,调用函数使该item成为当前最后一个完全可见的item

还有一点要注意,这个函数的实际效果是开启线程完成的,你直接在这个函数后面调用findFirstVisibleItemPosition的函数,得到的数据会是移动之前的数据,不是移动之后得到的数据,需要用handler.postDelay延迟一下再执行

recyc.scrollToPosition(n)

获取某个可见item的View,这里要注意这个输入的参数的起点是以第一个可见item为标准的。

比如你当前第一可见item是6,最后可见item是12,你想要得到8对应的item,那就得传 2 

recyc.getChildAt(n-first)

滑动RecyclerView,调用这个函数可以看得到滑动的过程

recyc.smoothScrollBy(0,offSet)

 

一.如何实现联动

1.首先是点击主列表某个item,详情列表通过自动移动显示相应的item,并使其置顶

移动详情列表要分三种情况,和之前分析scrollToPosition一样,

(1)当目标item的在当前第一个完全可见item的上面时,调用scrollToPosition函数使该item置顶

            if(n<=first){
                recyc.scrollToPosition(n)
            }

(2)当目标item处于第一个完全可见的item和最后一个完全可见的item之间时,直接获取该item的view,再getTop,把RecyclerView往上移动top的距离

else if(n<=last){
                var offSet=recyc.getChildAt(n-first).top
                recyc.smoothScrollBy(0,offSet)
            }

(3)当目标item在当前最后一个完全可见的item的下面时,首先调用scrollToPosition使该item变成当前最后一个完全可见item,也是最后一个可见的item,然后使用handler延迟一下,再获取当前第一个可见和最后一个可见的位置,然后接下来的操作就是之前第二种情况的操作了

else{
                recyc.scrollToPosition(n)

                //这里要延迟一下,因为之前的scrollToPosition的实际功能是开子线程完成的,如果直接调findFirstVisibleItemPosition,获取的数据还是之前的
                handler.postDelayed(Runnable {
                    first=layoutM.findFirstVisibleItemPosition()
                    last=layoutM.findLastVisibleItemPosition()
                    Log.v("zzw"," rightclick:"+n+" first:"+first+" last:"+last)

                    if(recyc.getChildAt(last-first)==null){

                    }else{
                        var offSet=recyc.getChildAt(last-first).top
                        recyc.smoothScrollBy(0,offSet)
                    }

                },50)

            }

2.滑动详情列表,主列表自动滑动实现并且选中相应item

首先我们在详情列表滑动停止时,判断主列表应该移动到哪个item,我的规则是当前可见item里,属于title类型的item,位置最小的就是主列表应该对应的item(PS:和之前一样,只是需要细微改动)

               if(rightClick==false&& newState == RecyclerView.SCROLL_STATE_IDLE){
                   //判断当前子列表显示哪个id的内容
                   var now=0
                   var first= twoLayoutM.findFirstVisibleItemPosition()
                   if(twoData.get(first).isTitle){
                       now=twoData.get(first).id
                   }else{
                       if(twoData.get(first).id+1>oneData.get(oneData.size-1).id){
                           now=twoData.get(first).id
                       }else{
                           now=twoData.get(first).id+1
                       }
                   }


               }

然后滑动主列表,同样是三种情况

(1)当目标item的在当前第一个完全可见item的上面时,调用scrollToPosition函数使该item置顶,然后延迟一下,通过smoothScrollBy移动到列表中间

            if(n<=first){
                recyc.scrollToPosition(n)

                handler.postDelayed({
                    first=layoutM.findFirstVisibleItemPosition()
                    last=layoutM.findLastVisibleItemPosition()

                    if(recyc.getChildAt(last-first)==null){

                    }else{
                        var offSet=recyc.getChildAt(last-first).top
                        recyc.smoothScrollBy(0,-offSet/2)
                    }
                },50)
            }

(2)当目标item处于第一个完全可见的item和最后一个完全可见的item之间时,移动getTop二分之一的距离

            }else if(n<=last){
                var offSet=recyc.getChildAt(n-first).top
                recyc.smoothScrollBy(0,offSet/2)
            }

(3)当目标item在当前最后一个完全可见的item的下面时,首先调用scrollToPosition使该item变成当前最后一个完全可见item,也是最后一个可见的item,然后使用handler延迟一下,再获取当前第一个可见和最后一个可见的位置,然后接下来的操作就是之前第二种情况的操作了

                recyc.scrollToPosition(n)

                //这里要延迟一下,因为之前的scrollToPosition的实际功能是开子线程完成的,如果直接调findFirstVisibleItemPosition,获取的数据还是之前的
                handler.postDelayed(Runnable {
                    first=layoutM.findFirstVisibleItemPosition()
                    last=layoutM.findLastVisibleItemPosition()

                    if(recyc.getChildAt(last-first)==null){

                    }else{
                        var offSet=recyc.getChildAt(last-first).top
                        recyc.smoothScrollBy(0,offSet/2)
                    }

                },50)

3.切断双列表之间的循环联动

比如点击主列表,详情列表自动滑动,然后又引得主列表自动滑动。又或者首先滑动详情列表,引得主列表自动滑动,这又引得详情列表自动滑动

我们在点击主列表时,赋予一个rightClick变量为true

rightClick=true

然后详情列表滑动,滑动停止时,通过这个变量判断当前滑动是否因主列表引起

if(rightClick==false&& newState == RecyclerView.SCROLL_STATE_IDLE)

而当因主列表滑动而导致详情列表滑动结束时,赋予rightClick为false

else if(rightClick==true&& newState == RecyclerView.SCROLL_STATE_IDLE){
                   rightClick=false
               }else if(rightClick==true&&newState == RecyclerView.SCROLL_STATE_DRAGGING){
                   rightClick=false
               }

 

三.最后

大家详细的下代码看看(ps:项目地址在文章头部)

 

 

 

 

 

 

 

展开阅读全文

没有更多推荐了,返回首页