Skip to content

NestedScrollView's use of PrimaryScrollController breaks when there are multiple inner ScrollPositions #40740

Closed

Description

@azuddin

Other instances of these issues we have seen reported:


Hello guys,
I wrote a very basic app that has a SliverAppBar and 3 tabs wrapped inside NestedScrollView.
Whenever I scrolling the list up and the app bar showing, all other scroll position is reset.

here's my code:

import 'dart:io';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primaryColor: Colors.white,
      ),
      home: NewsScreen(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class NewsScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _NewsScreenState();
}

class _NewsScreenState extends State<NewsScreen> {
  final List<String> _tabs = <String>[
    "Featured",
    "Popular",
    "Latest",
  ];

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Scaffold(
        body: DefaultTabController(
          length: _tabs.length,
          child: NestedScrollView(
            headerSliverBuilder:
                (BuildContext context, bool innerBoxIsScrolled) {
              return <Widget>[
                SliverOverlapAbsorber(
                  handle:
                      NestedScrollView.sliverOverlapAbsorberHandleFor(context),
                  child: SliverSafeArea(
                    top: false,
                    bottom: Platform.isIOS ? false : true,
                    sliver: SliverAppBar(
                      title: Text('Tab Demo'),
                      floating: true,
                      pinned: true,
                      snap: true,
                      forceElevated: innerBoxIsScrolled,
                      bottom: TabBar(
                        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 NotificationListener<ScrollNotification>(
                        onNotification: (scrollNotification) {
                          return true;
                        },
                        child: CustomScrollView(
                          key: PageStorageKey<String>(name),
                          slivers: <Widget>[
                            SliverOverlapInjector(
                              handle: NestedScrollView
                                  .sliverOverlapAbsorberHandleFor(context),
                            ),
                            SliverPadding(
                              padding: const EdgeInsets.all(8.0),
                              sliver: SliverList(
                                delegate: SliverChildBuilderDelegate(
                                  (BuildContext context, int index) {
                                    return Column(
                                      children: <Widget>[
                                        Container(
                                          height: 150,
                                          width: double.infinity,
                                          color: Colors.blueGrey,
                                          child: Column(
                                            mainAxisAlignment:
                                                MainAxisAlignment.center,
                                            children: <Widget>[
                                              Text('$name $index')
                                            ],
                                          ),
                                        ),
                                        SizedBox(
                                          height: 8,
                                        )
                                      ],
                                    );
                                  },
                                  childCount: 30,
                                ),
                              ),
                            ),
                          ],
                        ),
                      );
                    },
                  ),
                );
              }).toList(),
            ),
          ),
        ),
      ),
    );
  }
}

Steps to Reproduce

  • Featured -> Scroll down to 5 -> Change Tab Popular -> Scroll down to 7 -> Change Tab Latest -> Scroll up until app bar shown -> Change to other Tab. (*on both ios/android)

screenshot

  • Featured -> Scroll down to 5 -> Change Tab Popular -> Scroll down to 7 -> Change Tab Latest -> Scroll down to 7 -> Change back to Tab Featured Scroll up to 4 -> Change to other Tab. (*on android only)

screenshot

*above will reset the scroll position of all tab bar view to 0

Analyzing cwbflutter...
No issues found! (ran in 4.8s)
[√] Flutter (Channel stable, v1.9.1+hotfix.2, on Microsoft Windows [Version 10.0.18362.356], locale en-MY)
    • Flutter version 1.9.1+hotfix.2 at C:\Users\LENOVO-Workstation\flutter
    • Framework revision 2d2a1ffec9 (11 days ago), 2019-09-06 18:39:49 -0700
    • Engine revision b863200c37
    • Dart version 2.5.0

 
[√] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at C:\Users\LENOVO-Workstation\AppData\Local\Android\Sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.3
    • ANDROID_HOME = C:\Users\LENOVO-Workstation\AppData\Local\Android\Sdk
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b03)
    • All Android licenses accepted.

[√] Android Studio (version 3.5)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin version 39.0.3
    • Dart plugin version 191.8423
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b03)

[√] VS Code (version 1.35.1)
    • VS Code at C:\Users\LENOVO-Workstation\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.4.1

[√] VS Code, 64-bit edition (version 1.38.1)
    • VS Code at C:\Program Files\Microsoft VS Code
    • Flutter extension version 3.4.1

[√] Connected device (1 available)
    • Android SDK built for x86 • emulator-5554 • android-x86 • Android 9 (API 28) (emulator)

• No issues found!

Activity

  1. changed the title [-]Scroll position for all tabview being reset when scrolling up inside NestedScrollView[/-] [+]Scroll position for all CustomScrollView inside TabBarView being reset when scrolling up to show SliverAppBar inside NestedScrollView[/+] on Sep 18, 2019
  2. escamoteur commented on Sep 18, 2019

    @escamoteur
    Contributor

    This is expected behaviour because TabBarView does not preserve the state of its children. It has nothing to do with that there is a SliverAppBar.
    According to https://api.flutter.dev/flutter/widgets/PageStorageKey-class.html you only assign the PageStorage keys to the ScrollView. you also assigned them to your TabBar, maybe that is a problem.

  3. added
    f: scrollingViewports, list views, slivers, etc.
    frameworkflutter/packages/flutter repository. See also f: labels.
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Sep 18, 2019
  4. azuddin commented on Sep 18, 2019

    @azuddin
    Author

    This is expected behaviour because TabBarView does not preserve the state of its children. It has nothing to do with that there is a SliverAppBar.
    According to https://api.flutter.dev/flutter/widgets/PageStorageKey-class.html you only assign the PageStorage keys to the ScrollView. you also assigned them to your TabBar, maybe that is a problem.

    removed the key on the tab bar, the problem still remain

  5. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Sep 18, 2019
  6. changed the title [-]Scroll position for all CustomScrollView inside TabBarView being reset when scrolling up to show SliverAppBar inside NestedScrollView[/-] [+]Scroll positions for all CustomScrollViews inside TabBarViews is reset when scrolling up inside NestedScrollView[/+] on Sep 18, 2019
  7. escamoteur commented on Sep 18, 2019

    @escamoteur
    Contributor

    Have you tried if that also happens if you don't use a NestedScrollView and place the tabs outside of the CustomScrollView?

  8. azuddin commented on Sep 18, 2019

    @azuddin
    Author

    Have you tried if that also happens if you don't use a NestedScrollView and place the tabs outside of the CustomScrollView?

    yes i tried and the tab bar working fine like so:

    import 'dart:io';
    
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primaryColor: Colors.white,
          ),
          home: NewsScreen(),
          debugShowCheckedModeBanner: false,
        );
      }
    }
    
    class NewsScreen extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _NewsScreenState();
    }
    
    class _NewsScreenState extends State<NewsScreen> {
      final List<String> _tabs = <String>[
        "Featured",
        "Popular",
        "Latest",
      ];
    
      @override
      Widget build(BuildContext context) {
        return Material(
          child: Scaffold(
            body: DefaultTabController(
              length: _tabs.length,
              child: Scaffold(
                appBar: AppBar(
                  bottom: TabBar(
                    tabs: _tabs.map((String name) => Tab(text: name)).toList(),
                  ),
                  title: Text('Tabs Demo'),
                ),
                body: TabBarView(
                  children: _tabs.map((String name) {
                    return SafeArea(
                      top: false,
                      bottom: false,
                      child: Builder(
                        builder: (BuildContext context) {
                          return NotificationListener<ScrollNotification>(
                            onNotification: (scrollNotification) {
                              return true;
                            },
                            child: CustomScrollView(
                              key: PageStorageKey<String>(name),
                              slivers: <Widget>[
                                SliverPadding(
                                  padding: const EdgeInsets.all(8.0),
                                  sliver: SliverList(
                                    delegate: SliverChildBuilderDelegate(
                                      (BuildContext context, int index) {
                                        return Column(
                                          children: <Widget>[
                                            Container(
                                              height: 150,
                                              width: double.infinity,
                                              color: Colors.blueGrey,
                                              child: Column(
                                                mainAxisAlignment:
                                                    MainAxisAlignment.center,
                                                children: <Widget>[
                                                  Text('$name $index')
                                                ],
                                              ),
                                            ),
                                            SizedBox(
                                              height: 8,
                                            )
                                          ],
                                        );
                                      },
                                      childCount: 30,
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          );
                        },
                      ),
                    );
                  }).toList(),
                ),
              ),
            ),
          ),
        );
      }
    }
    

    screenshot

    the problem is with NestedScrollView i think. I follow this example from the documentation, also facing same issue (which is the scroll position for all tab will be reset whenever any tab scrolled to top). https://api.flutter.dev/flutter/widgets/NestedScrollView-class.html#widgets.NestedScrollView.1

  9. escamoteur commented on Sep 18, 2019

    @escamoteur
    Contributor

    Thanks for verifying this.

  10. azuddin commented on Oct 16, 2019

    @azuddin
    Author

    Any progress on a fix for this?
    @escamoteur
    Cheers

  11. escamoteur commented on Oct 23, 2019

    @escamoteur
    Contributor

    @azuddin unfortuntely not

  12. added this to the milestone on Oct 23, 2019
  13. 96 remaining items

  14. added
    P3Issues that are less important to the Flutter project
    triaged-designTriaged by Design Languages team
    on Jul 3, 2024
  15. yuukiw00w commented on Jul 18, 2024

    @yuukiw00w

    @Piinks
    Why was the priority of this issue lowered to P3?
    I believe this issue is a critical bug and requires a prompt fix.
    If my proposed workaround is acceptable, could it be officially adopted?
    My proposed workaround involves modifying the NestedScrollView. If this is adopted, it will become difficult to incorporate official changes to the NestedScrollView. Therefore, this workaround is temporary until the official changes are reflected, and it is desirable to have it officially adopted as soon as possible.

  16. Junesui commented on Aug 3, 2024

    @Junesui

    Any update in this issue?

  17. rusyaev-dk commented on Aug 3, 2024

    @rusyaev-dk

    Ugh, no updates to this issue :(

  18. junesui912 commented on Sep 2, 2024

    @junesui912

    2024 is almost over. This problem has lasted for five years. Doesn't Flutter have any solution yet?

  19. wow-222 commented on Oct 27, 2024

    @wow-222

    This problem still exists...

  20. added a commit that references this issue on Nov 4, 2024
    9ee00ae
  21. nate-thegrate commented on Nov 4, 2024

    @nate-thegrate
    Contributor
  22. github-actions commented on Nov 18, 2024

    @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.

  23. locked as resolved and limited conversation to collaborators on Nov 18, 2024
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

    P3Issues that are less important to the Flutter projecta: qualityA truly polished experiencecustomer: crowdAffects or could affect many people, though not necessarily a specific customer.f: scrollingViewports, list views, slivers, etc.found in release: 3.13Found to occur in 3.13frameworkflutter/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/packagesr: solvedIssue is closed as solvedteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages teamworkaround availableThere is a workaround available to overcome the issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions