当前位置:   article > 正文

Flutter ListView优雅的获取第一个可见Item的Position_flutter listview定位第一个item

flutter listview定位第一个item

      Flutter给我们提供了丰富的控件和控制方法,但是也有不少问题,就这两天,我就遇到去获取ListView第一个可见Item的Position的问题,Flutter并没有提供方法,只能我们想办法,我记得有大佬说过ListView和Android的RecyleView一样,那ListView的ItemBuilder肯定是用多少创建多少,用哪个创建哪个,抱着试试的态度,我在ItemBuilder打印了一下,果然,他只创建当前要用的Item,下来我们看看我的思路

     我们首先考虑初始化了多少个Item,这个信息对我们又什么用呢?? 这个数据我们缓存成Items的位置数组“positions”,(例如初始化Item数量为 5  ,表示初始化了0-5  Position 的 Item),初始化完成后,ListView滑动时,builder会根据需要创建新的Item,回收不用的Item。 builder每添加一个Item(前面说过,用一个添加一个,已经初始化好的Item,builder不在创建,即不再执行创建方法),我们就在初始化时缓存的位置变量“positions”的基础上改动,那Position 数组就可以自行调整头和尾了。

       这样,我们就知道大概第一个可见Item就在数组变量“positions”的前几个,为什么说是前几个,而不是第一个,因为我们缓存的Position 包括 屏幕可见+缓存的,所以第一个并不一定时可见的。

       好了,讲了那么多,那怎么去知道初始化了多少个Item??? 在初始化时 ,我们不确定到底会 初始创建 多少Item,数组变量也不好创建, 所以我们用一个整形变量“memoryPosition”去记录 初始化创建 多少Item,好了,我们现在知道Item数量了(包括 屏幕可见+缓存的)。      初始化Item的数量我们知道了。接下来 我们找个合适的时机将Item数量 Position 缓存成List数组—>“positions”,我是在NotificationListener的ScroStartNotification里面缓存Position的。    positions数组可以自行调整头和尾 那不就更简单了  ,看代码 ↓↓↓↓

 

     注意:大家尽量把cacheEctent的值调小,缓存越小,后面获取position越快

  1. List<int> positions;
  2. int memoryPosition;
  3. child: new ListView.builder(
  4. cacheExtent: 30.0,
  5. itemBuilder: (context, index) {
  6. //根据positions==null来判断是否已经初始化
  7. if(positions!=null) {
  8. //已经初始化过的话 滑动自行调整头和尾
  9. if (index > positions.last) {
  10. positions.removeAt(0);
  11. positions.add(index);
  12. } else if (index < positions.first) {
  13. positions.removeLast();
  14. positions.insert(0, index);
  15. }
  16. }else{
  17. //记录初始化了多少个Item
  18. memoryPosition=index;
  19. }
  20. },),

  NotificationListener的ScroStartNotification里面将变量memoryPosition 缓存成数组 positions,看代码

  1. new NotificationListener(
  2. onNotification: (notification){
  3. if(notification is ScrollStartNotification){
  4. if(positions==null) {
  5. positions=new List();
  6. for(int i=0 ;i<=memoryPosition;i++){
  7. positions.add(i);
  8. }
  9. }
  10. }
  11. },
  12. child: new ListView.builder(),

这样我们就知道头和尾了,并实时更新,可是头不一定是第一个可见Item,有可能是缓存的item,那我们怎么办呢,

我当时在想 我在调用时 如果我让 ListView在屏幕的位置 和  Item在屏幕中的位置+Item的高度  做比较  如果Item可见 ,那么Item在屏幕中的位置+Item的高度肯定大于ListView在屏幕的位置 (大家别忘了给ListView和它的Item们设置Key哟),好了,我们看代码

  1. int firstChildPosition=positions.first;
  2. int lastChildPosition=positions.last;
  3. double chileGlobalPositionY;
  4. double chileHeight;
  5. //获取ListView在屏幕中的位置
  6. double listViewGlobalPositionY=listViewKey.currentContext.findRenderObject().getTransformTo(null).getTranslation().y;
  7. for(int i=firstChildPosition;i<=lastChildPosition;i++){
  8. if(adsorptionDatas[i].adsorptionKey.currentContext==null){
  9. continue;
  10. }
  11. //子控件在屏幕中的位置 用于计算第一个可见Item的位置
  12. chileGlobalPositionY=adsorptionDatas[i].adsorptionKey.currentContext.findRenderObject().getTransformTo(null).getTranslation().y;
  13. //控件高度 用于计算第一个可见Item的位置
  14. chileHeight=adsorptionDatas[i].adsorptionKey.currentContext.findRenderObject().paintBounds.size.height;
  15. //如果在屏幕中可见
  16. if(chileGlobalPositionY+chileHeight>listViewGlobalPositionY){
  17. //TODO i就是第一个可见Item的位置
  18. break;
  19. }
  20. }

这样,我们的第一个可见Item的位置就获取到了

详细代码可参考https://github.com/baoolong/PullToRefresh 吸顶布局模块的代码

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/383216?site
推荐阅读
相关标签
  

闽ICP备14008679号