5

I have a NavBar which I control via a Provider :

class BottomNavBarProvider extends ChangeNotifier {
  final PageController navigationController = PageController(initialPage: 0);
  int selectedTabIndex = 0;

  BottomNavBarProvider() {}

  void selectTab(int index) {
    navigationController.jumpToPage(index);
    selectedTabIndex = navigationController.page?.round() ?? 0;
    notifyListeners();
  }
}

Problem: I think the problem is that I am using a Provider to store my PageContrller so if I push to another page, where the BottomBar is used, it is always attached to the same one from the provider. So I guess I need a way to properly dispose the PageController. But how do I do that?

I am using it inside my ApplicationContainer:

class ApplicationContainer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    initSizeService(context);

    return Scaffold(
      body: PageView(
        controller:
            Provider.of<BottomNavBarProvider>(context).navigationController,
        children: <Widget>[
          HomePage(),
          EntryPage(),
          VitalsHistoryPage(
            Provider.of<VitalsHistoryProvider>(context),
          ),
          SettingsPage(),
        ],
        physics: NeverScrollableScrollPhysics(),
      ),
    );
  }
}

The problem is that I also have a Onboarding-Process in my app and at the last page of it I cam calling Navigator.pushReplacementNamed(context, '/'); which is handled by my Router:

  static Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(
          builder: (context) => ApplicationContainer(),
        );
        ...

But this crashes my NavBar:

The following assertion was thrown while handling a gesture: ScrollController attached to multiple scroll views. 'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 109 pos 12: '_positions.length == 1'

Here is the Stack:

When the exception was thrown, this was the stack #2 ScrollController.position package:flutter/…/widgets/scroll_controller.dart:109 #3 PageController.jumpToPage package:flutter/…/widgets/page_view.dart:206 #4 BottomNavBarProvider.selectTab package:onkobutler/providers/bottom_nav_bar_provider.dart:10 #5 BottomNavBarItem._fireOnTap package:onkobutler/…/bottom_navigation_bar/bottom_nav_bar_item.dart:34 #6 BottomNavBarItem.build. package:onkobutler/…/bottom_navigation_bar/bottom_nav_bar_item.dart:46

And the associated code:

  List<BottomNavBarItem> _buildBottomNavBarItems(BuildContext context) {
    return [
      BottomNavBarItem(
        index: 0,
        selectedIndex: Provider.of<BottomNavBarProvider>(context, listen: true)
            .selectedTabIndex,
        text: 'Startseite',
        iconBaseUrl: 'images/icons/home_',
        onTap:
            Provider.of<BottomNavBarProvider>(context, listen: false).selectTab,
      ),
      BottomNavBarItem(
        index: 1,
        selectedIndex: Provider.of<BottomNavBarProvider>(context, listen: true)
            .selectedTabIndex,
        text: 'Eintrag',
        iconBaseUrl: 'images/icons/add_black.png',
        hasDynamicIconColor: false,
        onTap: () {
          AppRouter.openEntryProcedure(context);
        },
      ),
      BottomNavBarItem(
        index: 2,
        selectedIndex: Provider.of<BottomNavBarProvider>(context, listen: true)
            .selectedTabIndex,
        text: 'Verlauf',
        iconBaseUrl: 'images/icons/progress_',
        onTap:
            Provider.of<BottomNavBarProvider>(context, listen: false).selectTab,
      ),
      BottomNavBarItem(
        index: 3,
        selectedIndex: Provider.of<BottomNavBarProvider>(context, listen: true)
            .selectedTabIndex,
        text: 'Einstellungen',
        iconBaseUrl: 'images/icons/settings_',
        onTap:
            Provider.of<BottomNavBarProvider>(context, listen: false).selectTab,
      ),
    ];
  }
  }

Why is this happening? What am I missing here?

Let me know if you need any more info!

Chris
  • 1,828
  • 6
  • 40
  • 108
  • @UjjwalRaijada `ApplicationController` . That is where the `ScrollController` is. – Chris May 12 '21 at 17:17
  • Can you post a minimal reproducible code? – iDecode May 15 '21 at 14:53
  • It is duplicate of https://stackoverflow.com/questions/52484710/flutter-scrollcontroller-attached-to-multiple-scroll-views – Alann Maulana May 16 '21 at 00:08
  • @AlannMaulana I don’t have ‚static‘ anywhere – Chris May 16 '21 at 00:10
  • I think it is the same. The error message shown that your `ScrollController` is attached to another scroll views. It's hard to see where the problem happen if you don't post minimal code, especially the widget where `ScrollController` be used. – Alann Maulana May 16 '21 at 01:31
  • @AlannMaulana I dont really have a specific `ScrollController`. The top code is all there is. – Chris May 17 '21 at 08:46
  • @AlannMaulana I updated my questoin – Chris May 17 '21 at 09:25
  • Yeah, I'm aware too that your `PageController` is not disposed. You can change `ApplicationController` to Stateful, so you can dispose it. – Alann Maulana May 17 '21 at 09:56
  • but my `pageController` is stored in the provider, so just disposing `ApplicationContrller` wouldnt change anything, would it? – Chris May 17 '21 at 10:07
  • 1
    Dude you don't have to store `pageController` in your provider. You should keep that in your `ApplicationController`. You can then easily dispose it in the **dispose** method. You should only keep the `selectedIndex` in the provider and inside your `selectTab` method the argument `index` should be enough to update the `selectedIndex`. – Abdur Rafay Saleem May 17 '21 at 17:45
  • 1
    Short answer you are doing it all wrong. Don’t put any widgets like your navbar inside provider. Use provider for your data structure only and you won’t have these kinds of problems. Unfortunately I think your are going to have lots of headaches related to that even if you solve this one problem. – Kent May 20 '21 at 06:11
  • You may make a wrong guess of the problem you met. I only find a problem in your code that: The `onTap` in your **BottomNavBarItem** use `ValueChanged`: `(int) => void` on 1,3,4 but the 2 use `VoidCallback`: `(void) => void` – yellowgray May 21 '21 at 05:51

0 Answers0