Android获取RecyclerView滑动距离方法详细讲解

作者:AllenC6 时间:2021-07-04 23:21:32 

先说能用的究极解决方案,大家着急的直接复制走,以后想了解再过来看

没有header,且所有Item的高度一致

private fun getScrollYDistance(recyclerView: RecyclerView): Int? {
       kotlin.runCatching {
           val layoutManager = recyclerView.layoutManager as LinearLayoutManager
           val position = layoutManager.findFirstVisibleItemPosition()
           val firstVisibleChildView = layoutManager.findViewByPosition(position)
           val itemHeight = firstVisibleChildView!!.height
           return position * itemHeight - firstVisibleChildView.top
       }
       return null
   }

有一个header,其他所有Item高度一致

var headerHeight = 0
   private fun getScrollYDistance(recyclerView: RecyclerView): Int? {
       kotlin.runCatching {
           val layoutManager = recyclerView.layoutManager as LinearLayoutManager
           val position = layoutManager.findFirstVisibleItemPosition()
           if (position == 0) {
               val headerView = layoutManager.findViewByPosition(0)
               headerHeight = headerView!!.height
           }
           val firstVisibleChildView = layoutManager.findViewByPosition(position)
           val itemHeight = firstVisibleChildView!!.height
           return if (position == 0) {
               position * itemHeight - firstVisibleChildView.top
           } else {
               (position - 1) * itemHeight - firstVisibleChildView.top + headerHeight
           }
       }
       return null
   }

有多个header,其他Item一致

Integer[] headerHeightArray;
   private int getScollYDistance(){
       LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getRecyclerView().getLayoutManager();
       // 获取第一个可见item的位置
       int position = layoutManager.findFirstVisibleItemPosition();
       // 获取第一个可见item
       View firstVisiableChildView = layoutManager.findViewByPosition(position);
       // 必须考虑有没有Header  预存下所有header的高度
       int headerCount = adapter.getHeaderCount();
       if (headerCount > 0) {
           if (headerHeightArray == null) {
               headerHeightArray = new Integer[headerCount];
           }
           if (position < headerCount) {
               View headerView_i = layoutManager.findViewByPosition(position);
               headerHeightArray[position] = headerView_i.getHeight();
           }
       }
       // 获取第一个可见item的高度
       int itemHeight = firstVisiableChildView.getHeight();
       // 获取第一个可见item的位置
       int distance = 0;
       if (position == 0) {
           distance = position * itemHeight - firstVisiableChildView.getTop();
       } else {
           int allHeaderHeight = 0;
           for (int i = 0; i < Math.min(position,headerCount); i++) {
               allHeaderHeight = allHeaderHeight + headerHeightArray[i];
           }
           distance = (position - Math.min(position,headerCount)) * itemHeight - firstVisiableChildView.getTop() + allHeaderHeight;
       }
       return distance;
   }

注意调用位置:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
               @Override
               public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                   super.onScrolled(recyclerView, dx, dy);
                   getScollYDistance();
               }
           });

试过的一些想法,都有一些问题,有的可以弥补,有的直接玩完

RecyclerView 虽然有getScrollX() 和 getScrollY(), 但是测试发现这两个函数总是返回0,太无语了。因此想到了下面几种方法来实现获取滑动距离:

利用OnScrollListener

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
           private int totalDy = ;
           @Override
           public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
               totalDy -= dy;
           }
       });

如代码所述,totalDy的确保存了 RecyclerView 的滑动距离,但是当我向下滑动 RecyclerView ,之后插入/删除/移动 Item 的时候,totalDy 就变得不精确了;比如删除或者插入新的Item,那么totalDy就不能再回归到 0了。这个可以通过当删除或者插入时来对totalDy进行加减相应的高度。

totalDy = recyclerView.computeVerticalScrollOffset();

然而compute方法计算出的并不是滑动的精确距离,stackOverflow上有答案解释其为 item 的平均高度 * 可见 item 数目,不是我们需要的精确距离。

totalDy = recyclerView.getChildAt().getTop();

依靠第一个item的滑动距离来进行动画的设置,但是根据该方法得出的 totalDy 在滑动到一定程度后清零。

这是因为recyclerViewl.getChildAt(0) 返回的永远是第一个可见的child,不是所有view list 的第一个child,因此这种用法是得不到滑动距离的。

另外下面这三种用法都是等价的,都是获取第一个可见的child:

LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
      View firstVisiableChildView = this.getChildAt();
      View firstVisiableChildView = layoutManager.getChildAt()
      int position = layoutManager.findFirstVisibleItemPosition();
      View firstVisiableChildView = layoutManager.getChildAt(position)

但是下面这种就不是获取第一个可见的child,而是获得所有view list 的第一个child。但是滑动一段距离后它总是返回null,即第一个child被recycle后,总是返回null。

//Don't use this function to get the first item, it will return null when the first item is recycled.
LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
View child2 = layoutManager.findViewByPosition();

来源:https://blog.csdn.net/m0_37707561/article/details/128641390

标签:Android,获取,RecyclerView,滑动,距离
0
投稿

猜你喜欢

  • C语言中的数据整除判断问题

    2023-08-28 20:36:09
  • Java的接口和抽象类深入理解

    2023-01-26 02:19:22
  • 详解Flutter中key的正确使用方式

    2021-11-05 04:31:02
  • C#遍历得到checkboxlist选中值和设置选中项的代码

    2022-10-25 20:52:22
  • C#中abstract的用法详解

    2021-07-08 21:53:46
  • java实现小猫钓鱼游戏

    2021-10-10 19:59:48
  • android实现扫码枪功能

    2022-08-28 21:33:35
  • c#唯一值渲染实例代码

    2023-09-06 06:54:16
  • 一文给你通俗易懂的讲解Java异常

    2021-12-20 14:40:56
  • C#实现文字转语音功能

    2022-06-18 13:07:59
  • Android 中 SwipeLayout一个展示条目底层菜单的侧滑控件源码解析

    2022-03-10 14:25:33
  • Java中Map与JSON数据之间的互相转化

    2021-10-26 01:56:19
  • C#检测上传文件真正类型的方法

    2021-10-28 11:32:59
  • SSM框架中测试单元的使用 spring整合Junit过程详解

    2022-07-01 14:46:48
  • Jar包冲突问题原理及解决方案

    2023-03-05 09:40:02
  • Java实现删除排序数组中重复元素的方法小结【三种方法比较】

    2023-09-28 15:21:48
  • SpringBoot+hutool实现图片验证码

    2021-06-17 02:55:27
  • android ListView结合xutils3仿微信实现下拉加载更多

    2023-11-29 11:11:50
  • Android NotificationListenerService 通知服务原理解析

    2022-03-29 05:34:29
  • Java贪吃蛇游戏完善版

    2023-04-12 03:07:53
  • asp之家 软件编程 m.aspxhome.com