一尘不染

Flutter tabsView和NestedScrollView滚动问题

flutter

我有一个“ NestedScrollView”,其中包含多个“
TabView”小部件,并且每个选项卡都有一个列表生成器。问题是,当我滚动浏览特定选项卡中的一个列表时,滚动位置会影响其他选项卡中的所有其他列表。

即使我确实将“ ScrollController”添加到每个listview(在选项卡中),选项卡滚动中的listBuilder也与“
NestedScrollView”分开,这是示例代码:

import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    home:     MyApp()
    ,
  )
);


class MyApp extends StatefulWidget{
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {

  TabController tabController;
  Widget _tabBarView;

  @override
  void initState() {
    super.initState();
    tabController = TabController(length: 2, vsync: this,);
    _tabBarView = TabBarView(
        children: [
          DemoTab(),
          DemoTab(),
        ]);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
          controller: ScrollController(keepScrollOffset: true),
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverList(
                delegate: SliverChildListDelegate(
                    [
                      Container(height: 300, color: Colors.blue)
                    ]
                ),
              ),
            ];
          },
          body: DefaultTabController(
            length: 2,
            child: Column(
              children: <Widget>[
                Expanded(
                  child: Container(
                      child: _tabBarView
                  ),
                ),
              ],
            ),
          )
      ),
    );
  }
}

class DemoTab extends StatefulWidget{
  DemoTabState createState() => DemoTabState();
}

class DemoTabState extends State<DemoTab> with AutomaticKeepAliveClientMixin<DemoTab>{
  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;


  @override
  Widget build(BuildContext context) {

    return ListView.builder(
      key: UniqueKey(),
      itemBuilder: (b, i) {
      return Container(
        height: 50,
        color: Colors.green,
        margin: EdgeInsets.only(bottom: 3),
        child: Text(i.toString(),),
      );
    }, itemCount: 30,) ;

  }
}

阅读 1381

收藏
2020-08-13

共1个答案

一尘不染

3天后,我发现这是解决此问题的最佳方法,但仍需要更多改进,因为sliver标头扩展和收缩太快,您可以改进代码,并与我们分享

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
  home: MyApp(),
));

class MyApp extends StatefulWidget {
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  TabController tabController;
  Widget _tabBarView;
  var scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    tabController = TabController(
      length: 2,
      vsync: this,
    );
    _tabBarView = TabBarView(children: [
      DemoTab(parentController : scrollController),
      DemoTab(parentController : scrollController),
    ]);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
          controller: scrollController,
          physics: ScrollPhysics(parent: PageScrollPhysics()),
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverList(
                delegate: SliverChildListDelegate(
                    [Container(height: 300, color: Colors.blue)]),
              ),
            ];
          },
          body: DefaultTabController(
            length: 2,
            child: Column(
              children: <Widget>[
                Container(
                  child: TabBar(labelColor: Colors.grey, tabs: [
                    Tab(
                      text: 'One',
                    ),
                    Tab(
                      text: 'two',
                    )
                  ]),
                ),
                Expanded(
                  child: Container(child: _tabBarView),
                ),
              ],
            ),
          )),
    );
  }
}

class DemoTab extends StatefulWidget {

  DemoTab({ 
    this.parentController
  });

  final ScrollController parentController;


  DemoTabState createState() => DemoTabState();
}

class DemoTabState extends State<DemoTab>
    with AutomaticKeepAliveClientMixin<DemoTab> {
  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;

  ScrollController _scrollController;

  ScrollPhysics ph;
  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController();


    _scrollController.addListener((){


      var innerPos      = _scrollController.position.pixels;
      var maxOuterPos   = widget.parentController.position.maxScrollExtent;
      var currentOutPos = widget.parentController.position.pixels;

      if(innerPos >= 0 && currentOutPos < maxOuterPos) {

        //print("parent pos " + currentOutPos.toString() + "max parent pos " + maxOuterPos.toString());
        widget.parentController.position.jumpTo(innerPos+currentOutPos);

      }else{
        var currenParentPos = innerPos + currentOutPos;
        widget.parentController.position.jumpTo(currenParentPos);
      }


    });





    widget.parentController.addListener((){
      var currentOutPos = widget.parentController.position.pixels;
      if(currentOutPos <= 0) {
        _scrollController.position.jumpTo(0);
      }
    });


  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      key: UniqueKey(),
      controller: _scrollController,
      itemBuilder: (b, i) {
        return Container(
          height: 50,
          color: Colors.green,
          margin: EdgeInsets.only(bottom: 3),
          child: Text(
            i.toString(),
          ),
        );
      },
      itemCount: 30,
    );
  }
}
2020-08-13