Skip to content

RefreshIndicator syncs scrollposition across tabs when using TabbarView with AutomaticKeepAliveClientMixin inside NestedScrollView #62833

Closed

Description

@progratient

Use doc sample code for NestedScrollView , but have many problem.

  • If you don't set SliderAppBar's expandedHeight, listview inside tabbarview can't scroll vertical.
  • so I comment SliverOverlapAbsorber and SliverOverlapInjector code and can scroll vertical,
  • but for retain each page inside tabbarview, I use AutomaticKeepAliveClientMixin and wantKeepAlive set to true,
  • every page have a RefreshIndicator , when swip to refresh one page, other all page trigger onRefresh and show refresh progress at the same time and also all page scroll position all sync to the same position.
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,
      ),
    );
  }
}

```shell
D:\flutter-projects\my_flutter_app>flutter doctor -v
[√] Flutter (Channel stable, v1.17.5, on Microsoft Windows [Version 10.0.18363.959], locale zh-CN)
    • Flutter version 1.17.5 at D:\flutter
    • Framework revision 8af6b2f038 (5 weeks ago), 2020-06-30 12:53:55 -0700
    • Engine revision ee76268252
    • Dart version 2.8.4


[√] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
    • Android SDK at D:\Android\Sdk
    • Platform android-29, build-tools 29.0.3
    • ANDROID_HOME = D:\Android\Sdk
    • Java binary at: D:\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
    • All Android licenses accepted.

[√] Android Studio (version 4.0)
    • Android Studio at D:\Android\Android Studio
    • Flutter plugin version 48.0.2
    • Dart plugin version 193.7361
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)

[√] Connected device (1 available)
    • SM G973U1 • R38M202PE2A • android-arm64 • Android 10 (API 29)

• No issues found!

D:\flutter-projects\my_flutter_app>

Activity

  1. z759341385 commented on Aug 4, 2020

    @z759341385
  2. progratient commented on Aug 4, 2020

    @progratient
    Author

    you can try to use this packge
    https://pub.dev/packages/extended_nested_scroll_view#extendednestedscrollview

    Unfortunately, it seems does not solve these problems, am I right ?

    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> with SingleTickerProviderStateMixin {
      final List<String> _tabs = [
        "AAA",
        "BBB",
        "CCC",
        "DDD",
        "EEE",
        "FFF",
      ];
    
      TabController tcl;
    
      @override
      void initState() {
        super.initState();
        tcl = TabController(length: _tabs.length, vsync: this);
      }
    
      @override
      void dispose() {
        tcl.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        final double statusBarHeight = MediaQuery.of(context).padding.top;
        final double pinnedHeaderHeight = statusBarHeight + kToolbarHeight;
    
        return extended.NestedScrollView(
          pinnedHeaderSliverHeightBuilder: () {
            return pinnedHeaderHeight;
          },
          innerScrollPositionKeyBuilder: () => Key('${_tabs[tcl.index]}'),
            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: true,
                    snap: true,
                    // 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(
                      controller: tcl,
                      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(
              controller: tcl,
              // 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(key: Key(name)),
                          ),
                        ],
                      ), onRefresh: () => Future.delayed(Duration(seconds: 5)));
                    },
                  ),
                );
              }).toList(),
            ),
          );
      }
    }
    
    class TabPage extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _TabPageState();
      }
    
      TabPage({Key key}) : super(key: key);
    }
    
    class _TabPageState extends State<TabPage> with AutomaticKeepAliveClientMixin {
      @override
      bool get wantKeepAlive => true;
    
      @override
      Widget build(BuildContext context) {
        super.build(context);
        return extended.NestedScrollViewInnerScrollPositionKeyWidget(
            widget.key,
            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,
              ),
            ));
      }
    }
  3. changed the title [-]NestedScrollView + TabBarView + RefreshIndicator bug[/-] [+]RefreshIndicator has issues when using TabbarView with AutomaticKeepAliveClientMixin inside NestedScrollView[/+] on Aug 4, 2020
  4. TahaTesser commented on Aug 4, 2020

    @TahaTesser
    Contributor
    Code Sample
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    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,
          ),
        );
      }
    }
    
    
    flutter doctor -v
    [✓] Flutter (Channel master, 1.21.0-6.0.pre.160, on Mac OS X 10.15.6 19G73,
        locale en-GB)
        • Flutter version 1.21.0-6.0.pre.160 at /Users/taha/Code/flutter_master
        • Framework revision 31ee51a302 (10 hours ago), 2020-08-03 17:27:21 -0700
        • Engine revision fa16c3d0ba
        • Dart version 2.10.0 (build 2.10.0-2.0.dev 0f0e04ec3a)
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
        • Android SDK at /Users/taha/Code/sdk
        • Platform android-30, build-tools 30.0.1
        • ANDROID_HOME = /Users/taha/Code/sdk
        • Java binary at: /Applications/Android
          Studio.app/Contents/jre/jdk/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build
          1.8.0_242-release-1644-b3-6222593)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 11.6)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Xcode 11.6, Build version 11E708
        • CocoaPods version 1.9.3
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 4.0)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin version 48.0.2
        • Dart plugin version 193.7361
        • Java version OpenJDK Runtime Environment (build
          1.8.0_242-release-1644-b3-6222593)
    
    [✓] VS Code (version 1.47.3)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.13.1
    
     
    [✓] Connected device (5 available)            
        • Taha’s iPhone (mobile) • 00008020-001059882212002E            • ios            • iOS 13.6
        • iPhone 11 (mobile)     • 1EB615AF-5AB9-4AAA-A587-A6642BB79484 • ios            •
          com.apple.CoreSimulator.SimRuntime.iOS-13-6 (simulator)
        • macOS (desktop)        • macos                                • darwin-x64     • Mac OS X
          10.15.6 19G73
        • Web Server (web)       • web-server                           • web-javascript • Flutter Tools
        • Chrome (web)           • chrome                               • web-javascript • Google Chrome
          84.0.4147.105
    
    • No issues found!
    
  5. added
    p: material_uimaterial_ui package in flutter/packages
    f: scrollingViewports, list views, slivers, etc.
    frameworkflutter/packages/flutter repository. See also f: labels.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    on Aug 4, 2020
  6. ChihchengHsieh commented on Nov 10, 2020

    @ChihchengHsieh

    Any solution or workaround at this moment?

  7. gabrielCuringa commented on Jan 7, 2021

    @gabrielCuringa

    There is this post on StackOverflow which is two years old and doesn't seem to fix the problem... https://stackoverflow.com/questions/52264270/refreshindicator-with-nestedscrollview

  8. ingmferrer commented on Jan 17, 2021

    @ingmferrer

    Bump this

  9. lanrehnics commented on Jan 27, 2021

    @lanrehnics

    Any fix for this ?

  10. azazadev commented on May 15, 2021

    @azazadev

    any update ?

  11. TomJoe2021 commented on May 21, 2021

    @TomJoe2021

    anyone?

  12. 9 remaining items

  13. added
    P2Important issues not at the top of the work list
    on Jun 16, 2022
  14. kishan-dhankecha commented on Nov 21, 2022

    @kishan-dhankecha
    Contributor

    Any Update?

  15. icodeyou commented on Nov 22, 2022

    @icodeyou

    Any Update?

  16. Khurshidddbek commented on Dec 5, 2022

    @Khurshidddbek

    Developers we need an update.

  17. Ra3wej commented on Jan 2, 2023

    @Ra3wej

    setting

    primary=false
    of the tab that has the refresh indicator fixed the problem for me.
    maybe you can set all the tab`s primary attribute that you have to false ?
    image

  18. maheshj01 commented on Jan 10, 2023

    @maheshj01
    Member

    Reproducible on stable 3.3 and master 3.7

    • Scroll position is synced with the rest of the tabs
    • Refreshindicator refreshes all tabs
    code sample
    import 'package:flutter/material.dart';
    
    void main() => runApp(const MyApp());
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Demo'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key, required 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'),
                  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(
              children: _tabs.map((String name) {
                return SafeArea(
                  top: false,
                  bottom: false,
                  child: Builder(
                    builder: (BuildContext context) {
                      return RefreshIndicator(
                          child: CustomScrollView(
                            key: PageStorageKey<String>(name),
                            slivers: const <Widget>[
    //                      SliverOverlapInjector(
    //                        // This is the flip side of the SliverOverlapAbsorber
    //                        // above.
    //                        handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
    //                      ),
                              SliverPadding(
                                padding: EdgeInsets.all(0),
                                sliver: TabPage(),
                              ),
                            ],
                          ),
                          onRefresh: () =>
                              Future.delayed(const Duration(seconds: 5)));
                    },
                  ),
                );
              }).toList(),
            ),
          ),
        );
      }
    }
    
    class TabPage extends StatefulWidget {
      const TabPage({super.key});
    
      @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(
          itemExtent: 48.0,
          delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
              return Material(
                  child: ListTile(
                title: Text('Item $index'),
              ));
            },
            childCount: 30,
          ),
        );
      }
    }
    
    flutter doctor -v (mac)
    [✓] Flutter (Channel master, 3.7.0-13.0.pre.131, on macOS 13.1 22C65 darwin-arm64, locale en-IN)
        • Flutter version 3.7.0-13.0.pre.131 on channel master at /Users/mahesh/Development/flutter_master
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 0196e6050b (2 days ago), 2022-12-31 11:10:23 -0500
        • Engine revision 932591ec04
        • Dart version 3.0.0 (build 3.0.0-76.0.dev)
        • DevTools version 2.20.0
        • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks
          and upgrades.
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc4)
        • Android SDK at /Users/mahesh/Library/Android/sdk
        • Platform android-33, build-tools 33.0.0-rc4
        • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
        • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 14.0.1)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Build 14A400
        • CocoaPods version 1.11.3
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 2021.2)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    
    [✓] IntelliJ IDEA Community Edition (version 2021.2.1)
        • IntelliJ at /Applications/IntelliJ IDEA CE.app
        • Flutter plugin version 61.2.4
        • Dart plugin version 212.5080.8
    
    [✓] VS Code (version 1.74.2)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.56.0
    
    [✓] Connected device (3 available)
        • iPhone 12 Pro (mobile) • 026D5789-9E78-4AD5-B1B2-3F8D4E7F65E4 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-14-5 (simulator)
        • macOS (desktop)        • macos                                • darwin-arm64   • macOS 13.1 22C65 darwin-arm64
        • Chrome (web)           • chrome                               • web-javascript • Google Chrome 108.0.5359.124
    
    [✓] HTTP Host Availability
        • All required HTTP hosts are available
        
    • No issues found!
    
    [✓] Flutter (Channel stable, 3.3.9, on macOS 12.6 21G115 darwin-arm, locale en-IN)
        • Flutter version 3.3.9 on channel stable at /Users/mahesh/Development/flutter
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision b8f7f1f986 (24 hours ago), 2022-11-23 06:43:51 +0900
        • Engine revision 8f2221fbef
        • Dart version 2.18.5
        • DevTools version 2.15.0
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc4)
        • Android SDK at /Users/mahesh/Library/Android/sdk
        • Platform android-33, build-tools 33.0.0-rc4
        • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
        • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 14.0.1)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Build 14A400
        • CocoaPods version 1.11.3
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 2021.2)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    
    [✓] IntelliJ IDEA Community Edition (version 2021.2.1)
        • IntelliJ at /Applications/IntelliJ IDEA CE.app
        • Flutter plugin version 61.2.4
        • Dart plugin version 212.5080.8
    
    [✓] VS Code (version 1.70.2)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.53.20221101
    
    [✓] Connected device (3 available)
        • iPhone 12 Pro (mobile) • 026D5789-9E78-4AD5-B1B2-3F8D4E7F65E4 • ios            •
          com.apple.CoreSimulator.SimRuntime.iOS-14-5 (simulator)
        • macOS (desktop)        • macos                                • darwin-arm64   • macOS 12.6 21G115 darwin-arm
        • Chrome (web)           • chrome                               • web-javascript • Google Chrome 107.0.5304.110
    
    [✓] HTTP Host Availability
        • All required HTTP hosts are available
    
    • No issues found!
    
  19. changed the title [-]RefreshIndicator has issues when using TabbarView with AutomaticKeepAliveClientMixin inside NestedScrollView[/-] [+]RefreshIndicator syncs scrollposition across tabs when using TabbarView with AutomaticKeepAliveClientMixin inside NestedScrollView[/+] on Jan 10, 2023
  20. Piinks commented on May 30, 2023

    @Piinks
    Contributor

    Referring to OP here:

    If you don't set SliderAppBar's expandedHeight, listview inside tabbarview can't scroll vertical.

    This should be fixed by #127718

    every page have a RefreshIndicator , when swipe to refresh one page, other all page trigger onRefresh and show refresh progress at the same time and also all page scroll position all sync to the same position.

    The root of this issue is #40740, so I am going to close this issue to refer there for updates, we try to consolidate dupes to focus everything in one issue. Thanks for reporting and providing updates! Let's follow up over there. :)

  21. github-actions commented on Jun 13, 2023

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  22. locked as resolved and limited conversation to collaborators on Jun 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listf: scrollingViewports, list views, slivers, etc.found in release: 3.3Found to occur in 3.3found in release: 3.7Found to occur in 3.7frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: material_uimaterial_ui package in flutter/packages

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions