Flutter:当嵌套的ListView滚动到底部时,如何继续在顶部ListView中滚动

5
我希望创建以下内容:当到达内部Listview的顶部或底部时,我想继续在顶部的Listview中滚动。查看GIF:
一个选项是,在达到底部(使用控制器上的侦听器)时将内部Listview的物理效果设置为NeverScrollablePhysics,但如果您想再次向上滚动,则此选项将不起作用。
请参见下面的代码,提前感谢! 目前的GIF
class TestAppHomePage extends StatefulWidget {
@override
TestAppHomePageState createState() => new TestAppHomePageState();
}

class TestAppHomePageState extends State<TestAppHomePage> {


 ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    print('set up');
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: Container(
        color: Colors.green,
        child: ListView(
          primary: false,
          // controller: _scrollController,
          children: <Widget>[topWidget(), topWidget(), topWidget(), topWidget()],
        ),
      ),
    );
  }

  Widget topWidget() {
    return Card(
        color: Colors.purple,
        margin: EdgeInsets.all(16),
        child: Container(
          height: 400,
          child: Column(
            children: <Widget>[
              Container(height: 100, color: Colors.white),
              Expanded(
                  child: ListView(
                      controller: _scrollController,
                      children: List.generate(
                        40,
                        (index) {
                          return someText(index);
                        },
                      ).toList()))
            ],
          ),
        ));
  }

  Widget someText(int i) {
    return Text('text no $i');
  }
}

有人解决了这个问题吗? - Vitaly
我也需要它。如果我们设置 shrinkWrap: true,它会破坏 ListView 中的重用机制。如果项目数量很大,这将非常缓慢。 - Siyi Guo
请查看此答案:https://dev59.com/4VIH5IYBdhLWcg3wNayz#60611242,它为我解决了问题。 - Tristan Pct
1个回答

6
我和OP在同一个项目上工作,但目前还没有人回复,所以我想分享一下我的摸索、思考过程以及已经完成的内容。我会更新这个答案。
首先,我试图避免创建大量模板代码的解决方案,但恐怕我可能做得有些过头了。我相当确定我的解决方案不正确,因为编译器给出了警告。
毫不犹豫地说,我的想法是:
1. 我需要一种方法来捕获用户在内部列表中的输入,因此创建自定义ScrollPhysics是有意义的。
2. 内部列表在所有情况下都正常工作非常重要。因此,它始终调用super来处理。
3. 我需要传递一个接受我捕获的输入并假装确切传递到外部列表的函数。
结果请参见此Gif
// imports and stuff..

class CustomScroll extends BouncingScrollPhysics { 
  final Function outerController;
  CustomScroll({this.outerController, ScrollPhysics parent}): super(parent: parent);
  @override
  CustomScroll applyTo(ScrollPhysics ancestor) {
    return CustomScroll(
        outerController: outerController,  parent: buildParent(ancestor));
  }
  @override 
  Simulation createBallisticSimulation(ScrollMetrics position, double velocity) {
    if (position.pixels >= position.maxScrollExtent && velocity >= 0.0) {
      outerController(velocity);
    }
    return super.createBallisticSimulation(position, velocity);
  }
}

class ListInAList extends StatefulWidget {
  createState() => ListInAListState();
}
class ListInAListState extends State<ListInAList> with TickerProviderStateMixin {
  List<ScrollController> innerControllers = List();
  ScrollController outerController = ScrollController();
  final outerPhysics = BouncingScrollPhysics();
  void innerListener(double velocity, ScrollController outerController)
  {

    final sim = outerPhysics.createBallisticSimulation(outerController.position, velocity);
    ScrollActivity _test = BallisticScrollActivity(outerController.position.activity.delegate,sim,this);
    if (_test != null)
    outerController.position.beginActivity(_test);

  }

  Widget build(BuildContext context) {
    return ListView.builder(
        itemBuilder: buildItem, controller: outerController, itemCount: 4, physics: outerPhysics);
  }

  Widget buildItem(BuildContext context, int index) {
    final innerController = ScrollController();
    innerControllers.add(innerController);

    return Column(children: [
      Container(height: 100, color: Colors.blue),
      ListView.builder(
        physics: CustomScroll(outerController: (velocity) => innerListener(velocity, outerController)),
        itemBuilder: buildLoremImpsum,
        controller: innerController,
        itemCount: 20),
    ]);
  }
  Widget buildLoremImpsum(context, index) {
    return Container(
        height: 30,
        color: (index % 2 == 0)
            ? Color.fromRGBO(255, 0, 0, 1)
            : Color.fromRGBO(255, 255, 0, 1));
  }
}

基本上,只有 createBallisticSimulation 和函数 innerListener 是代码中真正有趣的部分,其他所有内容都只是示例的一部分。


你能否提供一个完整的例子吗?我是Flutter的新手。拜托了! - Jamshed Alam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接