Navigating between screens based on the Provider value change in Flutter

Issue

I have a flutter application with BLE communication. I’ve put BLE-related variables and functions in a Provider class. My screens’ structure is as follows:

Home -> ModeSelect -> NormalMode -> NormalDataShow

                   |

                   -> CustomMode -> CustomModeShow

The device which is under our control has pushbuttons as well. So whenever the user pushes a button, the BLE data should be discarded and the app should go to the ModeSelect screen.

So if we are in NormalDataShow or CustomMode screens, for example, and the user pushes the button, these screens should be closed and the app must go back to the ModeSelect automatically.

The device send a packet each time the user pushes the button. I currently receive this packet and can handle its value change in Provider class.

My question is that: How I can navigate between screens after such events?

I have tried this but everything is messed up and _Failed assertion: line 1995 pos 12: ‘!debugLocked’ error occurs:

@override
  Widget build(BuildContext context) {
    final _bleProvider = Provider.of<BLEProvider>(context, listen: true);
    if (_bleProvider.modeChanged == true) {
      _bleProvider.modeChanged = false;
      _bleProvider.resetScore();
  
      Navigator.of(context).popAndPushNamed('mode');
      return Container();
    } else
      return ... // The page main scaffold

Solution

I would take an approach similar to the BottomNavigationBar example from the Flutter team.

Basically, have a single Scaffold that changes its properties (primarily body) based on the value of your provider.

For example:

enum Page { a, b ,c }

/// This is the private State class that goes with MyStatefulWidget.
class BleApp extends StatelessWidget {
  final Map<Page, Widget> _widgets = {
    Page.a: Text('a'),
    Page.b: Text('b'),
    Page.c: Text('c'),
  };
  
  @override
  Widget build(BuildContext context) {
    final _bleProvider = Provider.of<BLEProvider>(context, listen: true);
    // Determine what page to show
    final page = Page.a;
    
    return Scaffold(
      appBar: AppBar(
        title: const Text('BLE App'),
      ),
      body: _widgets[page],
    );
  }
}

This is a simplified example but should help you get started.

Answered By – Alex Hartford

Answer Checked By – Marie Seifert (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.