I'm new to Flutter and confused about how InheritedWidget works with routes. I'm using an SQLite database with the sqflite library. Basically, what I'm trying to achieve is, when my app is launched, I want all widgets that don't require the database to show right away. For instance, the bottomNavigationBar of my Scaffold doesn't need the database but the body does. So I want the bottomNavigationBar to show right away, and a CircularProgressIndicator to be shown in the body. Once the database is open, I want the body to show content loaded from the database.
So, in my attempt to achieve this, I use FutureBuilder before my Scaffold to open the database. While the Future is not completed, I pass null for the drawer and a CircularProgressBar for the body, and the bottomNavigationBar as normal. When the Future completes, I wrap the drawer and body (called HomePage) both with their own InheritedWidget (called DataAccessor). This seems to work, as I can access the DataAccessor in my HomePage widget. But, when I use the Navigator in my drawer to navigate to my SettingsScreen, my DataAccessor is not accessible and returns null.
Here's some example code, not using a database but just a 5 second delayed Future:
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
future: Future.delayed(Duration(seconds: 5)),
builder: (context, snapshot) {
Widget drawer;
Widget body;
if (snapshot.connectionState == ConnectionState.done) {
drawer = DataAccessor(
child: Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text("Settings"),
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SettingsScreen()))
)
]
)
)
);
body = DataAccessor(child: HomePage());
}
else {
drawer = null;
body = Center(child: CircularProgressIndicator());
}
return Scaffold(
drawer: drawer,
body: body,
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Container(), title: Text("One")),
BottomNavigationBarItem(icon: Container(), title: Text("Two"))
]
)
);
}
)
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
DataAccessor dataAccessor = DataAccessor.of(context); //dataAccessor IS NOT null here
print("HomePage: ${dataAccessor == null}");
return Text("HomePage");
}
}
class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
DataAccessor dataAccessor = DataAccessor.of(context); //dataAccessor IS null here
print("SettingsScreen: ${dataAccessor == null}");
return Text("SettingsScreen");
}
}
class DataAccessor extends InheritedWidget {
DataAccessor({Key key, Widget child}) : super(key: key, child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) => false;
static DataAccessor of(BuildContext context) => context.inheritFromWidgetOfExactType(DataAccessor);
}
It's possible I'm doing things wrong. Not sure how good of practice storing widgets in variables is. Or using the same InheritedWidget twice? I've also tried wrapping the entire Scaffold with my DataAccessor (and having the database as null while it is loading), but the issue still remains where I can't get my DataAccessor in my SettingsScreen.
I've read that a possible solution is to put my InheritedWidget before the MaterialApp but I don't want to resort to this. I don't want a whole new screen to show while my database is opening, I want my widgets that don't need the database to be shown. This should be possible somehow.
Thanks!