首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >颤振NestedScrollView + TabBarView + RefreshIndicator bug

颤振NestedScrollView + TabBarView + RefreshIndicator bug
EN

Stack Overflow用户
提问于 2020-08-04 01:58:32
回答 1查看 2K关注 0票数 2

使用NestedScrollView的文档示例代码,但存在许多问题.

如果不设置SliderAppBar的

  • ,则列表视图不能垂直滚动。因此,

  • 注释SliverOverlapAbsorber和SliverOverlapInjector代码,并可以垂直滚动,

  • ,但是为了在选项卡视图中保留每个页面,我使用AutomaticKeepAliveClientMixin和wantKeepAlive设置为true,

  • 每个页面都有一个RefreshIndicator,当swip刷新一个页面时,其他所有页面触发onRefresh,同时显示刷新进度,以及所有页面滚动位置都同步到同一位置。

代码语言:javascript
运行
复制
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<String> _tabs = [
    "AAA",
    "BBB",
    "CCC",
    "DDD",
    "EEE",
    "FFF",
  ];

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: _tabs.length, // This is the number of tabs.
      child: NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          // These are the slivers that show up in the "outer" scroll view.
          return <Widget>[
//            SliverOverlapAbsorber(
              // This widget takes the overlapping behavior of the SliverAppBar,
              // and redirects it to the SliverOverlapInjector below. If it is
              // missing, then it is possible for the nested "inner" scroll view
              // below to end up under the SliverAppBar even when the inner
              // scroll view thinks it has not been scrolled.
              // This is not necessary if the "headerSliverBuilder" only builds
              // widgets that do not overlap the next sliver.
//              handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
//              sliver:
          SliverAppBar(
                title: const Text('Books'), // This is the title in the app bar.
                pinned: true,
                floating: false,
                snap: false,
                // The "forceElevated" property causes the SliverAppBar to show
                // a shadow. The "innerBoxIsScrolled" parameter is true when the
                // inner scroll view is scrolled beyond its "zero" point, i.e.
                // when it appears to be scrolled below the SliverAppBar.
                // Without this, there are cases where the shadow would appear
                // or not appear inappropriately, because the SliverAppBar is
                // not actually aware of the precise position of the inner
                // scroll views.
                forceElevated: innerBoxIsScrolled,
                bottom: TabBar(
                  isScrollable: true,
                  // These are the widgets to put in each tab in the tab bar.
                  tabs: _tabs.map((String name) => Tab(text: name)).toList(),
                ),
              ),
//            ),
          ];
        },
        body: TabBarView(
          // These are the contents of the tab views, below the tabs.
          children: _tabs.map((String name) {
            return SafeArea(
              top: false,
              bottom: false,
              child: Builder(
                // This Builder is needed to provide a BuildContext that is
                // "inside" the NestedScrollView, so that
                // sliverOverlapAbsorberHandleFor() can find the
                // NestedScrollView.
                builder: (BuildContext context) {
                  return RefreshIndicator(child: CustomScrollView(
                    // The "controller" and "primary" members should be left
                    // unset, so that the NestedScrollView can control this
                    // inner scroll view.
                    // If the "controller" property is set, then this scroll
                    // view will not be associated with the NestedScrollView.
                    // The PageStorageKey should be unique to this ScrollView;
                    // it allows the list to remember its scroll position when
                    // the tab view is not on the screen.
                    key: PageStorageKey<String>(name),
                    slivers: <Widget>[
//                      SliverOverlapInjector(
//                        // This is the flip side of the SliverOverlapAbsorber
//                        // above.
//                        handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
//                      ),
                      SliverPadding(
                        padding: const EdgeInsets.all(0),
                        // In this example, the inner scroll view has
                        // fixed-height list items, hence the use of
                        // SliverFixedExtentList. However, one could use any
                        // sliver widget here, e.g. SliverList or SliverGrid.
                        sliver: TabPage(),
                      ),
                    ],
                  ), onRefresh: () => Future.delayed(Duration(seconds: 5)));
                },
              ),
            );
          }).toList(),
        ),
      ),
    );

  }
}

class TabPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _TabPageState();
  }

}

class _TabPageState extends State<TabPage> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return SliverFixedExtentList(
      // The items in this example are fixed to 48 pixels
      // high. This matches the Material Design spec for
      // ListTile widgets.
      itemExtent: 48.0,
      delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
          // This builder is called for each child.
          // In this example, we just number each list item.
          return Material(child: ListTile(
            title: Text('Item $index'),
          ));
        },
        // The childCount of the SliverChildBuilderDelegate
        // specifies how many children this inner list
        // has. In this example, each tab has a list of
        // exactly 30 items, but this is arbitrary.
        childCount: 30,
      ),
    );
  }
}
EN

回答 1

Stack Overflow用户

发布于 2020-11-26 08:19:51

若要解决使用SliverOverlapAbsorber时的垂直滚动问题,请将这一行添加到SliverOverlapAbsorber之上。

SliverToBoxAdapter(child: Container(height: 0.1,),),

不知道为什么会发生,但这是我能想出的解决办法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63239203

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档