Flutter tabsView 和 NestedScrollView 滚动问题

标签 flutter flutter-layout flutter-sliver

我有一个“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,) ;

  }
}

最佳答案

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

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,
    );
  }
}

关于Flutter tabsView 和 NestedScrollView 滚动问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54689594/

相关文章:

flutter - ListView 中的Flutter组合框项目

Android Studio(未安装),当在机器上安装 Android Studio 时运行 flutter 医生

flutter - VSCode Ctrl+Space 不显示 Dart 的类选项

flutter - 向下滚动时隐藏底部导航栏,反之亦然

dart - Flutter:折叠 FlexibleSpaceBar 时更改文本

dart - 关闭 Listview.builder 的可滚动功能

Flutter 使用 FutureBuilder 我们如何创建具有延迟加载或更多加载元素调用 Web 服务的列表

flutter crossAxisAlignment 与 mainAxisAlignment

flutter - 从外部Dart文件 flutter 装饰输入字段

flutter - 将 DraggableScrollableSheet 添加到 Sliver 页面的底部