Skip to content

Wrapping a Scrollbar around a TabBar throws error The Scrollbar's ScrollController has no ScrollPosition attached. #124608

Closed

Description

@zogol

Wrapping a Scrollbar around a TabBar works but throws a console error

The Scrollbar's ScrollController has no ScrollPosition attached.
A Scrollbar cannot be painted without a ScrollPosition.

The Scrollbar attempted to use the PrimaryScrollController. This ScrollController should be associated with the ScrollView that the Scrollbar is being applied to.A ScrollView with an Axis.vertical ScrollDirection on mobile platforms will automatically use the PrimaryScrollController if the user has not provided a ScrollController. To use the PrimaryScrollController explicitly, set ScrollView.primary to true for the Scrollable widget.

The fix described in this commend #97873 (comment) does not work because a tabcontroller cannot be applied to a scrollcontroller

PreferredSize(
              preferredSize: const Size.fromHeight(55),
              child: RawScrollbar(
                //controller: PrimaryScrollController.of(context),
                //padding: EdgeInsets.all(5),
                mainAxisMargin: 5,
                trackVisibility: false,
                thumbColor: Theme.of(context).focusColor,
                thickness: 3,
                thumbVisibility: true,
                interactive: false,
                scrollbarOrientation: ScrollbarOrientation.top,
                child: TabBar(
                  padding: const EdgeInsets.only(top: 5),
                  controller: _tabController,
                  labelPadding: const EdgeInsets.symmetric(horizontal: 20),
                  //padding: const EdgeInsets.only(top: 5,bottom: 5, left: 5, right: 5),
                  labelColor: Theme.of(context).colorScheme.primary,
                  labelStyle: Theme.of(context).textTheme.titleMedium,
                  isScrollable: true,
                  unselectedLabelColor:
                      Theme.of(context).focusColor.withOpacity(0.7),
                  indicatorColor: Theme.of(context).colorScheme.primary,
                  tabs: __tabs,
                ),
              ),
            ),

Working with Channel stable, 3.7.10 and the issue appears on all platforms

Activity

  1. darshankawar commented on Apr 12, 2023

    @darshankawar
    Member

    @zogol
    TabBarView is also scrollable, so if you are wrapping Scrollbar around it, it might be causing conflict on scroll and hence the error could likely being thrown.

    Can you provide us your use case for which you need to wrap scrollbar around tabbar ?
    Also read this https://api.flutter.dev/flutter/widgets/NestedScrollView-class.html and see if it helps in your use case.

  2. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Apr 12, 2023
  3. zogol commented on Apr 13, 2023

    @zogol
    Author

    The practical example in which I would apply it would be the following.
    I have a tabbar with a large number of tabs. and similar to long vertically scrollable lists I would like to show my users an indicator where they are located inside the TabBar.

    Recording.2023-04-13.101446.2.mp4
  4. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Apr 13, 2023
  5. darshankawar commented on Apr 13, 2023

    @darshankawar
    Member

    @zogol
    Did you get a chance to look at NestedScrollView and see if it helps in implementing your use case ?

  6. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Apr 13, 2023
  7. zogol commented on Apr 21, 2023

    @zogol
    Author

    @darshankawar .no but i am not a professional in flutter yet either...

    i found another practical example right here on the github tabbar which also shows a scroll indicator.

    Screen_Recording_20230420_160511_Chrome.mp4
  8. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Apr 21, 2023
  9. darshankawar commented on Apr 24, 2023

    @darshankawar
    Member

    Thanks for the feedback. Please provide us a minimal code sample that throws the reported error so that we can analyze the issue further.

  10. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Apr 24, 2023
  11. zogol commented on May 1, 2023

    @zogol
    Author
    import 'package:any_link_preview/any_link_preview.dart';
    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(
            // This is the theme of your application.
            //
            // Try running your application with "flutter run". You'll see the
            // application has a blue toolbar. Then, without quitting the app, try
            // changing the primarySwatch below to Colors.green and then invoke
            // "hot reload" (press "r" in the console where you ran "flutter run",
            // or simply save your changes to "hot reload" in a Flutter IDE).
            // Notice that the counter didn't reset back to zero; the application
            // is not restarted.
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key, required this.title});
    
      // This widget is the home page of your application. It is stateful, meaning
      // that it has a State object (defined below) that contains fields that affect
      // how it looks.
    
      // This class is the configuration for the state. It holds the values (in this
      // case the title) provided by the parent (in this case the App widget) and
      // used by the build method of the State. Fields in a Widget subclass are
      // always marked "final".
    
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage>
        with SingleTickerProviderStateMixin {
      late final TabController _tabController;
    
       final Map<Widget, Widget> _tabs = {
         const Tab(
           height: 50,
           text: "Tab (Tab)",
           iconMargin: EdgeInsets.zero,
           icon: Icon(Icons.tab),
         ): const Center(
           child: Text("Tab"),
         ),
         const Tab(
           height: 50,
           text: "Tab (Tab)",
           iconMargin: EdgeInsets.zero,
           icon: Icon(Icons.tab),
         ): const Center(
           child: Text("Tab"),
         ),
         const Tab(
           height: 50,
           text: "Tab (Tab)",
           iconMargin: EdgeInsets.zero,
           icon: Icon(Icons.tab),
         ): const Center(
           child: Text("Tab"),
         ),
         const Tab(
           height: 50,
           text: "Tab (Tab)",
           iconMargin: EdgeInsets.zero,
           icon: Icon(Icons.tab),
         ): const Center(
           child: Text("Tab"),
         ),
         const Tab(
           height: 50,
           text: "Tab (Tab)",
           iconMargin: EdgeInsets.zero,
           icon: Icon(Icons.tab),
         ): const Center(
           child: Text("Tab"),
         ),
         const Tab(
           height: 50,
           text: "Tab (Tab)",
           iconMargin: EdgeInsets.zero,
           icon: Icon(Icons.tab),
         ): const Center(
           child: Text("Tab"),
         ),
         const Tab(
           height: 50,
           text: "Tab (Tab)",
           iconMargin: EdgeInsets.zero,
           icon: Icon(Icons.tab),
         ): const Center(
           child: Text("Tab"),
         ),
         const Tab(
           height: 50,
           text: "Tab (Tab)",
           iconMargin: EdgeInsets.zero,
           icon: Icon(Icons.tab),
         ): const Center(
           child: Text("Tab"),
         ),
       };
    
      @override
      void initState() {
    
        _tabController = TabController(
          animationDuration: const Duration(milliseconds: 200),
          initialIndex: 0,
          length: _tabs.length,
          vsync: this,
        );
    
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            bottom: PreferredSize(
              preferredSize: const Size.fromHeight(55),
              child:
              RawScrollbar(
                mainAxisMargin: 5,
                trackVisibility: false,
                thickness: 1,
                thumbVisibility: true,
                interactive: false,
                scrollbarOrientation: ScrollbarOrientation.top,
                child:
                TabBar(
                  padding: const EdgeInsets.only(top: 5),
                  controller: _tabController,
                  labelPadding: const EdgeInsets.symmetric(horizontal: 20),
                  isScrollable: true,
                  unselectedLabelColor:
                      Theme.of(context).focusColor.withOpacity(0.7),
                  tabs: _tabs.keys.toList(),
                ),
              ),
    
          ),),
          body: TabBarView(
              controller: _tabController,
              children: _tabs.values.toList()),
        );
      }
    }
    
    
  12. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on May 1, 2023
  13. darshankawar commented on May 2, 2023

    @darshankawar
    Member

    Thanks for the update. Please switch to latest master and try again to see if issue still persists or not. Also check this comment / solution to see if it works in your case or not.

  14. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on May 2, 2023
  15. 15 remaining items

  16. Ferrb9579 commented on Oct 8, 2023

    @Ferrb9579
      scrollbarOrientation: ScrollbarOrientation.right,
      radius: Radius.circular(100.h),
      mainAxisMargin: 2.h,
      thumbVisibility: true,
      controller: Scontroller,
      child: ListView.builder(
        // primary: true,
        controller: Scontroller,
        itemCount: _warehouseListedData.value?.map((e) => e["godown"]).toSet().toList().length,
        scrollDirection: Axis.vertical,
        shrinkWrap: true,
        padding: EdgeInsets.all(0.5.h),
        itemBuilder: (context, index) {
          return Container(
            width: double.infinity,
            margin: EdgeInsets.all(1.w),
            padding: EdgeInsets.symmetric(vertical: 1.h, horizontal: 2.w),
            decoration: BoxDecoration(color: Color.fromRGBO(34, 34, 34, 1), borderRadius: BorderRadius.circular(1.h)),
            child: Column(
              children: [
                IntrinsicHeight(
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      RichText(
                        text: TextSpan(
                          children: [
                            TextSpan(text: "GODOWN: ", style: TextStyle(fontSize: 18, decoration: TextDecoration.none, color: Colors.red, fontWeight: FontWeight.w500)),
                            TextSpan(text: "${_warehouseListedData.value?.map((e) => e["godown"]).toSet().toList()[index]}", style: TextStyle(fontSize: 20, decoration: TextDecoration.none, color: Colors.red, fontWeight: FontWeight.w600)),
                          ],
                        ),
                      ),
                      AspectRatio(
                        aspectRatio: 1,
                        child: Container(
                          decoration: BoxDecoration(borderRadius: BorderRadius.circular(0.5.h), border: Border.all(color: Color.fromARGB(255, 75, 75, 75), width: 2.5), color: Colors.white),
                          child: Center(
                            child: Padding(
                              padding: EdgeInsets.all(1.0.w),
                              child: Text(
                                "ALL",
                                style: TextStyle(fontWeight: FontWeight.w700, decoration: TextDecoration.none),
                              ),
                            ),
                          ),
                        ),
                      )
                    ],
                  ),
                ),
                SizedBox(
                  height: 1.h,
                ),
                Column(
                  children: () {
                    List<Widget> widgets = [];
    
                    var thisGodown = _warehouseListedData.value?.map((e) => e["godown"]).toSet().toList()[index];
                    var thisGodownCompartments = _warehouseListedData.value
                        ?.map((e) {
                          if (e["godown"] == thisGodown) {
                            return e["compartment"];
                          }
                        })
                        .toSet()
                        .whereType<String>()
                        .toList();
                    for (var compartment in thisGodownCompartments!) {
                      var thisCompartmentLocations = _warehouseListedData.value
                          ?.map((e) {
                            if (e["godown"] == thisGodown && e["compartment"] == compartment) {
                              return e["location"];
                            }
                          })
                          .toSet()
                          .whereType<String>()
                          .toList();
                      print(thisCompartmentLocations.toString());
                      ScrollController sc = ScrollController();
                      widgets.add(
                        Container(
                          height: 6.h,
                          margin: EdgeInsets.symmetric(horizontal: 0.5.w),
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(1.h),
                            color: Color.fromARGB(255, 69, 69, 69),
                          ),
                          child: RawScrollbar(
                            controller: sc,
                            thumbVisibility: true,
                            scrollbarOrientation: ScrollbarOrientation.bottom,
                            child: ListView.builder(
                              // primary: true,
                              controller: sc,
                              shrinkWrap: true,
    
                              scrollDirection: Axis.horizontal,
                              itemCount: thisCompartmentLocations?.length,
                              itemBuilder: (context, index) {
                                return AspectRatio(
                                  aspectRatio: 1,
                                  child: Container(
                                    margin: EdgeInsets.symmetric(vertical: 2.w, horizontal: 2.w),
                                    decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(1.w)),
                                  ),
                                );
                              },
                            ),
                          ),
                        ), // TODO
                      );
                      widgets.add(SizedBox(
                        height: 1.h,
                      ));
                    }
                    // print(thisGodownCompartments.toString());
                    return widgets;
                  }(),
                )
              ],
            ),
          );
        },
      ),
    )
    

    Sorry I was lazy to destructure. Hope someone finds it useful

    The Scrollbar and ListView must contain same ScrollController.
    The ListView Physics should not be defined

  17. self-assigned this
    on Dec 17, 2025
  18. removed their assignment
    on Jan 16, 2026
  19. github-actions commented on Mar 4, 2026

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

  20. locked as resolved and limited conversation to collaborators on Mar 4, 2026
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 lista: error messageError messages from the Flutter frameworkf: scrollingViewports, list views, slivers, etc.found in release: 3.10Found to occur in 3.10found in release: 3.11Found to occur in 3.11frameworkflutter/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/packagesteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions