How to Hide bottom navigation bar using provider flutter - flutter

I am working on a social media app which contains a home screen with bottom navbar and 5 pages .
Although i am able to change the bool value to show or hide navbar under provider but the changes are not reflecting in widget .
main.dart -
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) =>
ScrollProvider(),
),
],
child : MyApp()
My provider class -
class ScrollProvider with ChangeNotifier{
bool isVisible = true;
void show() {
isVisible = true;
print("in Provider $isVisible");
notifyListeners();
}
void hide() {
isVisible = false;
print("in Provider $isVisible");
notifyListeners();
}
}
Page which has the value scrollcontroller
ScrollController _scrollController =
ScrollController();
_scrollController.addListener(() {
final direction =
_scrollController.position.userScrollDirection;
if (direction == ScrollDirection.forward) {
ScrollProvider().show();
}
if (direction == ScrollDirection.reverse) {
ScrollProvider().hide();
}
});
And my homescreen which which has body and navbar contains this code
‘’’
bottomNavigationBar: Consumer<BottomBarVisibilityProvider>(
builder: (context, bottomBarVisibilityProvider, child) =>
AnimatedContainer(
duration: const Duration(milliseconds: 200),
child: bottomBarVisibilityProvider.isVisible
? Wrap(
children: const [BottomBar()],
)
: Wrap(),
),
),
I have initialised the provider inside main.dart
Can someone tell me why its not working .. and what should i do
here is the full code of homepage
class _HomeState extends State<Home> {
List<Widget> _pages ;
#override
void initState() {
super.initState();
_pages = [
MemeTabView(scrollController: scrollToHide),
TempTab(),
null,
NotificationScreen(),
ProfileScreen(uid: FirebaseAuth.instance.currentUser.uid,showAppBar: false),
];
}
#override
Widget build(BuildContext context) {
if (widget.selectedIndex == null) {
widget.selectedIndex = 0;
}
return
Scaffold(
appBar: AppBar(
title: brandName(),
),
extendBody: true,
bottomNavigationBar:
Consumer<ScrollProvider>(
builder: (_,scrollProvider,__){
return Container(
child: scrollProvider.isVisible == true
?
bottomNav()
: Container(),
);
},
),
drawer: MyDrawer(),
body:PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
children: _pages,
),
);
}

You need to read provider like
context.read<BottomBarVisibilityProvider>();
void main() {
runApp(
/// Providers are above [MyApp] instead of inside it, so that tests
/// can use [MyApp] while mocking the providers
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => BottomBarVisibilityProvider()),
],
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.\
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: const SCCR(),
);
}
}
class SCCR extends StatefulWidget {
const SCCR({Key? key}) : super(key: key);
#override
State<SCCR> createState() => _SCCRState();
}
class _SCCRState extends State<SCCR> {
//just for test purpose
late final bottomBarVisibilityProvider =
context.read<BottomBarVisibilityProvider>();
late final ScrollController scrollController = ScrollController()
..addListener(() {
final direction = scrollController.position.userScrollDirection;
if (direction == ScrollDirection.forward) {
if (!bottomBarVisibilityProvider.isVisible) {
bottomBarVisibilityProvider.show();
}
} else if (direction == ScrollDirection.reverse) {
if (bottomBarVisibilityProvider.isVisible) {
bottomBarVisibilityProvider.hide();
}
}
});
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
controller: scrollController,
child: Container(
height: 3333,
),
),
bottomNavigationBar: Consumer<BottomBarVisibilityProvider>(
builder: (context, bottomBarVisibilityProvider, child) =>
AnimatedContainer(
duration: const Duration(milliseconds: 200),
child: bottomBarVisibilityProvider.isVisible
? Wrap(
children: [
Container(
height: 100,
color: Colors.red,
width: 100,
)
],
)
: null,
),
),
);
}
}
I will suggest to follow documentation

This is how I use my providers:
I have 3 different providers here, MyThemeClass, NewMsgListener and FirebaseProvider. All of them extend ChangeNotifierProvider. And this is my main:
import 'package:my_app/my_firebase.dart';
import 'package:my_app/global.dart';
import 'package:provider/provider.dart';
import 'package:navigation_history_observer/navigation_history_observer.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:my_app/firebase_options.dart';
import 'package:my_app/screens/welcome_screen.dart';
import 'package:my_app/new_msg_listener.dart';
import 'package:my_app/provider_updates.dart';
import 'package:my_app/theme.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
MyFirebase.myFutureFirebaseApp =
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
final NewMsgListener newMsgListener = NewMsgListener();
final MyThemeClass myThemeClass = MyThemeClass();
await myThemeClass.getMyTheme();
print('getMyTheme() is ready');
await MyFirebase.myFutureFirebaseApp;
runApp(MyApp(myThemeClass, newMsgListener));
}
class MyApp extends StatelessWidget {
const MyApp(this.myThemeClass, this.newMsgListener, {Key? key})
: super(key: key);
final MyThemeClass myThemeClass;
final NewMsgListener newMsgListener;
#override
Widget build(BuildContext context) {
print('Building $runtimeType');
FirebaseProvider firebaseProvider = FirebaseProvider();
firebaseProvider.initialize(GlobalVariable.navState);
return MultiProvider(
providers: [
ChangeNotifierProvider<FirebaseProvider>(
create: (context) => firebaseProvider),
ChangeNotifierProvider(create: (context) => myThemeClass),
ChangeNotifierProvider(create: (context) => newMsgListener),
],
builder: (context, child) {
return MaterialApp(
theme: Provider.of<MyThemeClass>(context).currentTheme,
home: WelcomeScreen(myThemeClass),
debugShowCheckedModeBanner: false,
navigatorObservers: [NavigationHistoryObserver()],
navigatorKey: GlobalVariable.navState,
);
});
}
}
Not that it's important, but my my_firebase.dart file looks like this (just so you don't need to wonder!):
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:my_app/firebase_labels.dart';
class MyFirebase {
static Future<FirebaseApp>? myFutureFirebaseApp; //Initialized from main()
static FirebaseFirestore storeObject = FirebaseFirestore.instance;
static auth.FirebaseAuth authObject = auth.FirebaseAuth.instance;
}
Does that provider management work for you?

Related

how to use a shared preference from a change notifier

I'm trying to get my head around the shared preference package from a change notifier. here is my code:
Future<void> main() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => GlobalSettings1(prefs: prefs)),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
'/': (context) => Page01(),
});
}
}
class Page01 extends StatefulWidget {
const Page01({Key? key}) : super(key: key);
#override
State<Page01> createState() => _Page01State();
}
class _Page01State extends State<Page01> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: 30,),
InkWell(
onTap: () {
context.read<GlobalSettings1>().ToggleSwitch();
},
child: Container(
height: 30,
width: 80,
color: context.watch<GlobalSettings1>().toggleSwitch01
? Colors.green
: Colors.red,
),
),
],
),
);
}
}
and here is my change notifier:
class GlobalSettings1 with ChangeNotifier {
bool _toggleSwitch01 = true;
final SharedPreferences prefs;
GlobalSettings1({required this.prefs});
bool get toggleSwitch01 => _toggleSwitch01;
void ToggleSwitch() {
_toggleSwitch01 = !_toggleSwitch01;
_setPrefItems();
notifyListeners();
}
void _setPrefItems() {
prefs.setBool('toggleSwitch01', _toggleSwitch01);
notifyListeners();
}
void _getPrefItems() {
_toggleSwitch01 = prefs.getBool('toggleSwitch01') ?? true;
notifyListeners();
}
bool getToggleSwitch01() {
_getPrefItems();
return _toggleSwitch01;
}
}
How do i use setprefitems and getprefitems in my code to make it so the toggleswitch01 bools state is saved for when the app is closed and then statrted again?
thanks so much

Flutter build not behaving as expected

I'm trying to make a note app but there is a yellow square showing on the screen.
I've included the main.dart code and also allnotesscreens.dart. I think there is something wrong with allnotesscreens code, but I don't know what.
Maybe _loadViewMode() part.
Why this problem is happening?!!!
Main.dart:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'providers/label_provider.dart';
import 'providers/note_provider.dart';
import 'package:provider/provider.dart';
import 'constants/app_constants.dart';
import 'screens/all_labels_screen.dart';
import 'screens/all_notes_screen.dart';
import 'screens/drawer_screen.dart';
main() {
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: ColorsConstant.grayColor,
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => NoteProvider()),
ChangeNotifierProvider(create: (_) => LabelProvider()),
],
builder: (context, child) => MaterialApp(
title: 'Note-App',
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.dark,
theme: customThemeData(context),
initialRoute: '/',
routes: {
'/': (context) => const AllNotesScreen(),
DrawerScreen.routeName: (context) => const DrawerScreen(),
AllLabelsScreen.routeName: (context) => const AllLabelsScreen(),
},
),
);
}
}
allnotesscreens.dart:
class AllNotesScreen extends StatefulWidget {
const AllNotesScreen({Key? key}) : super(key: key);
#override
State<AllNotesScreen> createState() => _AllNotesScreenState();
}
class _AllNotesScreenState extends State<AllNotesScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
Container(
height: 200,
width: 100,
color: Colors.yellow,
),
),
);
}
String _viewMode = ViewMode.staggeredGrid.name;
bool _isLoading = false;
final _scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
setState(() {
_isLoading = true;
});
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
Future _loadViewMode() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('view-mode')) return;
setState(() {
_viewMode = prefs.getString('view-mode') ?? ViewMode.staggeredGrid.name;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text(
"all notes",
style: TextStyleConstants.titleAppBarStyle,
),
actions: [
if (context
.watch<NoteProvider>()
.items
.isNotEmpty)
IconButton(
onPressed: () {
showSearch(
context: context,
delegate: NoteSearch(isNoteByLabel: false),
);
},
icon: const Icon(Icons.search),
),
IconButton(
onPressed: () async {
final result = await changeViewMode(_viewMode);
setState(() {
_viewMode = result;
});
},
icon: _viewMode == ViewMode.staggeredGrid.name
? const Icon(Icons.view_stream)
: const Icon(Icons.grid_view),
),
const SizedBox(
width: 6,
)
],
),
drawer: const DrawerScreen(),
body: _isLoading
? const Center(
child: CircularProgressIndicator(),
)
: RefreshIndicator(
onRefresh: () => refreshOrGetData(context),
child: Consumer<NoteProvider>(
builder: (context, noteProvider, child) =>
noteProvider.items.isNotEmpty
? NoteListViewWidget(
notes: noteProvider.items,
viewMode: _viewMode,
scaffoldContext: _scaffoldKey.currentContext!,
)
: child!,
child: const NoNoteUIWidget(
title: "your notes after adding will appear here",
),
),
),
floatingActionButton: FloatingActionButton(
child: linearGradientIconAdd,
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const EditNoteScreen(),
));
},
),
);
}
}
}
The first few lines of your _AllNotesScreenState class are why there's a yellow square; that's what you're telling it to build.
class _AllNotesScreenState extends State<AllNotesScreen> {
// this build function here is what is drawing to the screen
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
Container(
height: 200,
width: 100,
color: Colors.yellow,
),
),
);
}
Maybe it's just how you've pasted it in, but it appears as though you have a build function defined within the didChangeDependencies function. If you took it out of there, it would then make it apparent that you have two build functions defined for the class.
I'm assuming it's the second one that you actually want building.
#override
void didChangeDependencies() {
super.didChangeDependencies();
Future _loadViewMode() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('view-mode')) return;
setState(() {
_viewMode = prefs.getString('view-mode') ?? ViewMode.staggeredGrid.name;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
...

Redirect user to login form if the user is not logged in

I made a web app and deployed it to firebase. Let's say that the link is https://firebasewebapp. When I open the link the Sign In form shows up but when I open https://firebasewebapp/#/home I get redirected to the home page even if the user is not logged in. Is there a way to redirect the user if it's not logged in? I use Flutter 2.10.3 Stable Channel
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: options),
);
runApp(MultiProvider(providers: [
], child: const MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Portalul e-Radauti',
theme: ThemeData(
primarySwatch: Colors.orange,
textButtonTheme: TextButtonThemeData(
style: ButtonStyle(
backgroundColor:
MaterialStateColor.resolveWith((states) => Colors.orange),
foregroundColor:
MaterialStateColor.resolveWith((states) => Colors.white),
),
),
),
initialRoute: '/login',
routes: {
'/home': (_) => const MyHomePage(),
'/addcouncilmember': (_) => const LocalCouncilLayout(),
'/signup': (_) => const SignUp(),
'/login': (_) => const LogIn(),
'/addevent': (_) => const AddEventLayout(),
'/profile': (_) => const Profile(),
},
// home: const MyApp(),
);
}
}
The easiest way to do this would be to use Flutter's Navigator 2.0 or a package which wrap Navigator 2.0's API such as go_router or beamer.
Here's an example of how you can implement this behavior by using go_router:
router.dart
import 'package:go_router/go_router.dart';
import 'app.dart';
import 'redirection/log_in.dart';
import 'redirection/my_home_page.dart';
import 'redirection/sign_up.dart';
GoRouter routerGenerator(LoggedInStateInfo loggedInState) {
return GoRouter(
initialLocation: Routes.login,
refreshListenable: loggedInState,
redirect: (state) {
final isOnLogin = state.location == Routes.login;
final isOnSignUp = state.location == Routes.signup;
final isLoggedIn = loggedInState.isLoggedIn;
if (!isOnLogin && !isOnSignUp && !isLoggedIn) return Routes.login;
if ((isOnLogin || isOnSignUp) && isLoggedIn) return Routes.home;
return null;
},
routes: [
GoRoute(
path: Routes.home,
builder: (_, __) => const MyHomePage(),
),
GoRoute(
path: Routes.login,
builder: (_, __) => LogIn(loggedInState),
),
GoRoute(
path: Routes.signup,
builder: (_, __) => SignUp(loggedInState),
),
],
);
}
abstract class Routes {
static const home = '/home';
static const signup = '/signup';
static const login = '/login';
}
app.dart
import 'package:flutter/material.dart';
import 'router.dart';
class LoggedInStateInfo extends ChangeNotifier {
bool _isLoggedIn = false;
bool get isLoggedIn => _isLoggedIn;
void login() {
_isLoggedIn = true;
notifyListeners();
}
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _loggedInStateInfo = LoggedInStateInfo();
late final _router = routerGenerator(_loggedInStateInfo);
#override
void dispose() {
_loggedInStateInfo.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routeInformationParser: _router.routeInformationParser,
routerDelegate: _router.routerDelegate,
);
}
}
With this code you only need to update the value of _isLoggedIn inside the LoggedInStateInfo and notify the listeners to access the HomePage, otherwise you will only have access to the LogIn and SignUp pages even when you manually change the URL.
Bonus
LogIn page code
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../app.dart';
import '../router.dart';
class LogIn extends StatelessWidget {
final LoggedInStateInfo loggedInStateInfo;
const LogIn(this.loggedInStateInfo, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('LogIn')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: loggedInStateInfo.login,
child: const Text('Log In'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => context.push(Routes.signup),
child: const Text('Sign Up'),
),
],
),
),
);
}
}
SignUp page code
import 'package:flutter/material.dart';
import '../app.dart';
class SignUp extends StatelessWidget {
final LoggedInStateInfo loggedInStateInfo;
const SignUp(this.loggedInStateInfo, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('SignUp')),
body: Center(
child: ElevatedButton(
onPressed: loggedInStateInfo.login,
child: const Text('Sign Up'),
),
),
);
}
}

Can't add or update a list

So I'm trying to make a list that contains some widgets and then add a new widget to it when I press a button, but it doesn't seem to be working
This is the code:
class MessagesProvider extends ChangeNotifier{
List<dynamic> mesgs = [
new chatBubbleSend(),
new chatBubbleReceiver(),
new chatBubbleReceiver()
];
bool loading = true;
addMesg(){
mesgs.add(chatBubbleSend());
print(mesgs.length);
print(mesgs);
notifyListeners();
}
printMesg(){
print(mesgs.length);
print(mesgs);
}
removeMesg(){
mesgs.removeLast();
print(mesgs.length);
print(mesgs);
notifyListeners();
}
}
and this is what i get when i press the add, remove or print buttons
add,remove,print
and this is the list builder code
ChangeNotifierProvider<MessagesProvider>(
create: (context) => MessagesProvider(),
child: ChatMessages()
),
class ChatMessages extends StatelessWidget {
#override
Widget build(BuildContext context) {
final mesgs = Provider.of<MessagesProvider>(context, listen: false).mesgs;
return ListView.builder(
shrinkWrap: true,
itemCount: mesgs.length,
itemBuilder: (context,index)=> mesgs[index],
);
}
}
I have looking for a solution for over 8 hours now, and still, I couldn't fix it.
I jumped the gun with my first answer sorry.
When trying to recreate I ran into the same frustrating issue - focusing on the the provider being the problem until I realised it's actually the rendering of the updated list that's the issue.
You need to use a list builder to render the updating list in a change notifier consumer in a stateful widget
Full working example below:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class WidgetListProvider with ChangeNotifier {
List<Widget> widgets = [];
int listLength = 0;
void addWidget(){
Widget _widget = Text('Hello');
widgets.add(_widget);
listLength = widgets.length;
print('Added a widget');
notifyListeners();
}
void removeWidget(){
if (widgets.length > 0) {
widgets.removeLast();
listLength = widgets.length;
print('Removed a widget');
notifyListeners();
}
}
}
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Widget _appBar (BuildContext context) {
return AppBar(
title: Text('My App'),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar(context),
// You need to define widgets that update when a provider changes
// as children of a consumer of that provider
body: Consumer<WidgetListProvider>(builder: (context, widgetProvider, child){
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
RaisedButton(
child: Text('Add widget'),
onPressed: () {
widgetProvider.addWidget();
},
),
RaisedButton(
child: Text('Remove Widget'),
onPressed: () {
widgetProvider.removeWidget();
},
),
Row(
children: [
Text('Number of Widgets: '),
Text(widgetProvider.listLength.toString()),
],
),
Container(
height: MediaQuery.of(context).size.height*0.6,
child: ListView.builder(itemCount: widgetProvider.widgets.length, itemBuilder: (BuildContext context, int index){
return widgetProvider.widgets[index];
})
)
],
),
);
}
),
);
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => WidgetListProvider(),
child: MyApp(),
)
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: HomePage(),
);
}
}

Flutter : Navigator operation requested with a context that does not include a Navigator

I have a scenario wherein I check the value of SharePreferences based on the value it will redirect the user to HomePage or LandingPage. I am not sure where did I got wrong? but I am getting this error below: I guess its not getting the context right any idea how do I get it?.
Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
E/flutter (11533): The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
Here is my code:
import 'package:credit/src/pages/landing.dart';
import 'package:flutter/material.dart';
import 'package:credit/src/pages/credit/home.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<MyApp> {
#override
void initState() {
super.initState();
getUserStatus().then((userStatus) {
if (userStatus == null) {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return LandingPage();
}));
} else {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return HomePage();
}));
}
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: CircularProgressIndicator(),
));
}
}
Future<String> getUserStatus() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String userStatus = prefs.getString('userstatus');
print("==On Load Check ==");
print(userStatus);
return userStatus;
}
When you call Navigator.of(context) framework goes up in widget tree attached to provided context and tries to find the closest Navigator.
The widget tree you showed does not have one, so you need to include Navigator in the widget tree.
Easiest option is to use MaterialApp with your widget passed as home. MaterialApp is creating navigator inside itself. (CupertinoApp does it too)
Updated code from original example:
import 'package:credit/src/pages/landing.dart';
import 'package:flutter/material.dart';
import 'package:credit/src/pages/credit/home.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: LoadingPage(),
);
}
}
class LoadingPage extends StatefulWidget {
LoadingPage({Key key}) : super(key: key);
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<LoadingPage> { // note type update
#override
void initState() {
super.initState();
getUserStatus().then((userStatus) {
if (userStatus == null) {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return LandingPage();
}));
} else {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return HomePage();
}));
}
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: CircularProgressIndicator(),
));
}
}
Future<String> getUserStatus() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String userStatus = prefs.getString('userstatus');
print("==On Load Check ==");
print(userStatus);
return userStatus;
}
I have changed my code from
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo App',
theme: ThemeData(
primarySwatch: white,
scaffoldBackgroundColor: Colors.white,
),
home: Scaffold(
appBar: AppBar(
title: Text('Demo App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
HomeScreen(title: 'Demo Home')));
},
child: Text('Open Home Screen'))
],
),
),
),
);
}
To
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo App',
theme: ThemeData(
primarySwatch: white,
scaffoldBackgroundColor: Colors.white,
),
home: InitScreen());
}
}
class InitScreen extends StatelessWidget {
const InitScreen({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
HomeScreen(title: 'Demo Home')));
},
child: Text('Open Home Screen'))
],
),
),
);
}
What changed?
Create a separate widget for home code in MyApp with InitScreen
What was the issue?
When we try to push Route by using Navigator.of(context), flutter will
try to find Navigator in the widget tree of the given context. In the
initial code, there was no widget that has Navigator. So, create a
separate widget for home code. And the MaterialApp widget in MyApp
will have Navigator.