关于RecyclerView与ListView控件滑动距离的计算方法

本文介绍了如何计算RecyclerView与ListView的滑动距离,主要通过分析这两个控件的滑动原理,利用LayoutManager和滑动状态来计算滑动距离。文中给出了具体的代码实现,包括RecyclerView的computeRecyclerViewScrollDistance方法和ListView的computeListViewScrollDistance方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:Ken.He


由于项目需要,需要对各个app窗口中的控件进行滑动,并截图,最后拼接。其核心难点就在于滑动,包括它滑动的判断,滑动的距离计算等等。截图与拼接部分这里不详述。

计算滑动的距离,原理其实很简单,就是: 滑动后的位置(终点)- 滑动前的位置(起点)= 滑动距离。

这里介绍一下如何计算RecyclerView与ListView实际滑动距离(当前仅限由下向上滑动一种情况)。

一、RecyclerView:

     RecyclerView 作为一个新兴的列表控件,是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好。RecyclerView与ListView原理是类似的:都是仅仅维护少量的View并且可以展示大量的数据集。RecyclerView用以下两种方式简化了数据的展示和处理:

a.使用LayoutManager来确定每一个item的排列方式。

b.为增加和删除项目提供默认的动画效果。    

既然item都交给了LayoutManager来管理,那我们就从它入手。先来看一下需要用到的几个方法:

     findFirstVisibleItemPosition();//获取显示在屏幕上可见的第一个子View在列表上对应的position

     findLastVisibleItemPosition();//获取显示在屏幕上可见的最后一个子View在列表上对应的position

     findViewByPosition(int position);//通过已知的子view的position来获取子view

接下来,我们来了解一下计算过程,首先使用变量mLastVisibleItemPosition记录下当前状态下,最后一个子View的position来做为标识,然后通过findViewByPosition(int position);得到该子view,使用view.getTop()获取到该子View距离父视图顶部的距离并使用mLastVisibleItemTopValue记录下来。滑动后,判断mLastVisibleItemPosition是否大于初始值,如果是,则通过findViewByPosition(int position)方法获取之前记录的子view, 并取该子view当前的top值,计算mLastVisibleItemTopValue与当前top的差值,即本次滑动距离。以下附上代码(由于framework无法调用support包,所以只能通过反射来取得其方法,自定义RecyclerViewUtil): 

            privateint mLastVisibleItemPosition = 0;

            privateint mLastVisibleItemTopValue = 0;

            /**

             * add a method for compute scroll distance byrecyclerView

             */

             private intcomputeRecyclerViewScrollDistance(View recyclerView) {

                       intdistance = 0;

                       //if mLastVisibleItemPosition > 0 , mLastVisibleItemPosition's value is valid

                       if(mLastVisibleItemPosition> 0){

                                   //get top value after scroll

                                   ObjectoldPositionItem = RecyclerViewUtil.findViewByPosition(recyclerView,mLastVisibleItemPosition);

                                   if(oldPositionItem!= null){

                                               distance= mLastVisibleItemTopValue - ((View)oldPositionItem).getTop();

                                   }

                       }

                       //record current position of last visible item

                       Objectobj = RecyclerViewUtil.findLastVisibleItemPosition(recyclerView);

                       if(obj!= null){

                                   mLastVisibleItemPosition= ((Integer)obj).intValue();

                       }else{

                                   mLastVisibleItemPosition= 0;

                       }

                       ObjectnewPositionItem = RecyclerViewUtil.findViewByPosition(recyclerView,mLastVisibleItemPosition);

                       if(newPositionItem!= null){

                                   mLastVisibleItemTopValue= ((View)newPositionItem).getTop();

                       }

                       returndistance;

             }

 

二、ListView:

        ListView作为老牌势力,还是占有重要的地位,至少,实现一些对称性的列表,listView效率显得更高。闲话少说,直奔主题,我们要计算ListView的滑动距离,就必须先提一下ListView的滑动方式scrollListBy(int value), 如果使用scrollBy(intvalue)或者scrollTo(int x,int y)方法,listView不会滑动。

ListView滑动距离的计算原理也是一样,利用getFirstVisibleItemPosition()和getLastVisiblePosition(),getChildAt(int position)以及view.getTop()方法,值得一提的是,这里的position是ListView的子View的position,并非是所有子项,这是有区别的,我们都知道ListView的视图与数据dataItem是分离的,并非一一对应,所以我们需要用到getFirstVisibleItemPosition()这个方法,然后在获取滑动后作为标记的子View时,使用getChildAt(mLastVisibleItemPosition –firstVisiblePosition)方法,才能准确获取到滑动后的子View,然后取其top值与滑动前的top值进行计算,得出的结果就是滑动的距离。

     

      /**

       * add a method forcompute scroll distance by ListView

       */

      private int computeListViewScrollDistance(View listView){

                  if(listView == null){

                       return 0;

                  }

                  int distance = 0;

                  // if mLastVisibleItemPosition > 0 ,mLastVisibleItemPosition's value is valid

                  int firstVisiblePosition =((AbsListView)listView).getFirstVisiblePosition();

                  if(mLastVisibleItemPosition > 0){

                       // get top value after scroll

                       View oldPositionItem = ((AbsListView)listView).getChildAt(mLastVisibleItemPosition-firstVisiblePosition);

                       Log.e(TAG,"oldPositionItem="+oldPositionItem);

                       if(oldPositionItem != null){

                             distance = mLastVisibleItemTopValue -oldPositionItem.getTop();

                             Log.d(TAG, "---computeListViewScrollDistance---beforescroll:"+mLastVisibleItemTopValue+" afterscroll:"+oldPositionItem.getTop() +" distance:"+distance);

                       }

                  }

                  // record current position of last visible item

                  mLastVisibleItemPosition =((AbsListView)listView).getLastVisiblePosition();

                  View newPositionItem =((AbsListView)listView).getChildAt(mLastVisibleItemPosition-firstVisiblePosition);

                  Log.e(TAG,"newPositionItem="+newPositionItem);

                  if(newPositionItem != null){

                       mLastVisibleItemTopValue = newPositionItem.getTop();

                  }

                  Log.d(TAG,"---computeListViewScrollDistance---mLastVisibleItemPosition="+mLastVisibleItemPosition+" mLastVisibleItemTopValue="+mLastVisibleItemTopValue +"distance="+distance);

                  return distance;

      }

补充:ScrollView可以直接使用其唯一的子View,然后利用view.getY(),滑动前与滑动后的值进行计算得出,但是现在单纯的ScrollView在线上几乎不可见。


总结:线性容器可以通过该原理进行计算,而固定式容器(如WebView、FrameLayout)则不适用该方法。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值