因为一个外包项目需要实现左右Listview的联动,比较类似于 饿了嘛商品页面的那种形式,左侧ListView点击后可以让右侧跳转至对应分类,右侧滚动时,左侧也会选择到对应的分类。

网上找了一段时间没有找到比较满意的适配空安全的版本,所以自己写了一个比较粗糙的。源码放在了:https://github.com/NeverOvO/flutterlinkagerollinglist

请参考源码后根据自己项目的实际需要来修改。理论上左右2个ListView可以放下任何形式的Widget。项目无任何依赖。

核心源码

//修改这里的数据会更改一页高度
const double leftItemHeight = 45; // 左边一个item的高度
const double rightItemTitleHeight = 38; // 右边一个标题的高度
const int leftWidgetFlex = 3; // 左边组件占据空间的比例
const int rightWidgetFlex = 9; // 右边组件占据空间的比例
const int rightGridViewCrossAxisCount = 3; //右侧GirdView一排数量,这里测试时为3

上述代码放在头部,来控制后面的代码中的部分高度和比例,修改这里会对计算右侧一页的高度产生影响

//右侧ListView的监听
    _rightListController.addListener((){

      //滚动超过右侧Listview的项目长度时,将左侧选中最后一项,这一个判断不添加的话,左侧ListView选择不到最后一项
      if(_rightOffSetStepList.last <= _rightListController.offset){
        setState(() {
          _indexLeft =  _rightOffSetStepList.length -1;
        });
      }else{
        for(int i = 0; i < _rightOffSetStepList.length ; i++){
          if(_rightOffSetStepList[i] > _rightListController.offset + 0.1){
            setState(() {
              _indexLeft =  (i - 1 < 0 ? 0 : ( i - 1) );
            });
            break;
          }
        }
      }
    });

上述代码为右侧ListView的监听部分,用这里来控制左侧ListView的选中项目

//计算右侧的一页高度
  void _calculation(){
    //这个数组用来计算单独一个List的页面高度
    List rightListStep = [];
    _rightOffSetStepList.clear();
    _rightGridItemHight = (MediaQuery.of(context).size.width - 20) * rightWidgetFlex / (leftWidgetFlex + rightWidgetFlex) / rightGridViewCrossAxisCount ;
    rightListStep.add((_rightGridItemHight * ( (ll[0] ~/ rightGridViewCrossAxisCount) + (ll[0] % rightGridViewCrossAxisCount == 0 ? 0 : 1)) + rightItemTitleHeight));
    for(int i =1; i<_left.length ; i++){
      rightListStep.add((_rightGridItemHight * ( (ll[i] ~/ rightGridViewCrossAxisCount) + (ll[i] % rightGridViewCrossAxisCount == 0 ? 0 : 1)) + rightItemTitleHeight));
    }

    _lastGridHeight = (MediaQuery.of(context).size.height - MediaQuery.of(context).padding.top - kBottomNavigationBarHeight) - rightListStep.last;


    for(int i =0;i< rightListStep.length  ; i++){
      double _off = 0.0;
      for(int j = 0; j < i ; j++){
        _off += rightListStep[j];
      }
      _rightOffSetStepList.add(_off);
    }
  }

上述代码为计算右侧ListView一页高度的核心代码。其中 rightListStep数组为计算一个分类的高度,为单独计算。

_rightOffSetStepList 在后续循环会使用rightListStep中的代码进行累加,这里实现的是点击左右ListView分类标题的时候,需要右侧跳转的高度,点击跳转的代码为:

_rightListController.animateTo(_rightOffSetStepList[index], duration: const Duration(milliseconds: 500), curve: Curves.easeIn);

_lastGridHeight为最后一项中SizedBox需要填充的高度,以避免最后一项不能被滑动上去的尴尬。

演示: