Flutter "context " Navigatior.pushedNamed generator RouteSettings - flutter

my Navigator.pushNamed does not work anymore since I refactored my BottomNavigationBar into a new class. The setState() works fine, so I strongly assume that there is a problem with the context. The BottomNavigationBar shows up in the app but it won't route me to the next page anymore. I am struggling for hours now to figure this out...
The error I get is:
Could not find a generator for route RouteSettings("...", null) in the _WidgetsAppState.
The NewBottomNavigationBar class
class NewBottomNavigationBar extends StatefulWidget {
#override
_NewBottomNavigationBarState createState() => _NewBottomNavigationBarState();
}
class _NewBottomNavigationBarState extends State<NewBottomNavigationBar> {
int _selectedTab = 0;
final _selectedTabList = [
TheSlateScreen.id,
Search.id,
LoginScreen.id,
];
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
currentIndex: _selectedTab,
onTap: (int index) {
setState(() {
_selectedTab = index;
});
Navigator.pushNamed(
context,
_selectedTabList[_selectedTab].toString(),
);
},
unselectedItemColor: kSlate,
items: const <BottomNavigationBarItem>[
......
The class where I use the NewBottomNavigation()
class TheSlateScreen extends StatefulWidget {
static const String id = 'theslate_screen';
#override
_TheSlateScreenState createState() => _TheSlateScreenState();
}
class _TheSlateScreenState extends State<TheSlateScreen> {
#override
Widget build(BuildContext context) {
screenWidth = MediaQuery.of(context).size.width;
screenHeight = MediaQuery.of(context).size.height;
return MaterialApp(
home: Scaffold(
bottomNavigationBar: NewBottomNavigationBar(),
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
.....
The routes in my main.dart
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => SlateTasks(),
child: MaterialApp(
initialRoute: LoginScreen.id,
routes: {
LoginScreen.id: (context) => LoginScreen(),
RegistrationScreen.id: (context) => RegistrationScreen(),
TheSlateScreen.id: (context) => TheSlateScreen(),
ResetPasswordScreen.id: (context) => ResetPasswordScreen(),
Search.id: (context) => Search(),
},
));

Related

one Drawer for all screens in flutter web

i'm new to flutter and I want to create a web app with drawer and couple of screens.
here is my main function and root of apps ui:
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Tapchi Admin Panel',
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: bgColor,
textTheme: GoogleFonts.poppinsTextTheme(Theme
.of(context)
.textTheme)
.apply(bodyColor: Colors.white),
canvasColor: secondaryColor,
),
home: const DashboardScreen()
);
}
}
and here is my DashboardScreen:
class DashboardScreen extends StatelessWidget {
const DashboardScreen({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
);
}
}
and here is my SideMenu:
class SideMenu extends StatelessWidget {
const SideMenu({super.key});
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: [
const DrawerHeader(child: Icon(Icons.android)),
SideMenuItem(
title: 'dashboard',
leadingIcon: Icons.dashboard,
press: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DashboardScreen()));
}),
SideMenuItem(
title: 'users',
leadingIcon: Icons.person,
press: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const UserScreen()));
}),
],
),
);
}
}
my problem is when i navigate into DashboardScreen i lose AppBar and Drawer but I want to have them for entire application!.
in android we could solve this problem by using NavHost.
how can I have one Drawer for my whole app.
by the way i'm developing a webApp
Ok, I managed to do that using two MaterialApp widgets and a global navigatorKey variable. Here is an example:
import 'package:flutter/material.dart';
final navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return Sample();
}
}
class Sample extends StatelessWidget {
const Sample({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
drawer: SideMenu(),
// use new MaterialApp to push new (sub)screens on top of that area and preserve the same drawer
body: MaterialApp(
navigatorKey: navigatorKey,
home: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(child: Text('Home screen')),
),
);
}
}
class SideMenu extends Drawer {
const SideMenu({super.key});
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: [
const DrawerHeader(child: Icon(Icons.android)),
SideMenuItem(
title: 'dashboard',
leadingIcon: Icons.dashboard,
press: () {
Navigator.push(
navigatorKey.currentContext!,
MaterialPageRoute(
builder: (context) => const DashboardScreen()));
}),
SideMenuItem(
title: 'users',
leadingIcon: Icons.person,
press: () {
Navigator.push(
navigatorKey.currentContext!,
MaterialPageRoute(
builder: (context) => const UserScreen()));
}),
],
),
);
}
}
class SideMenuItem extends StatelessWidget {
final String title;
final IconData leadingIcon;
final Function() press;
const SideMenuItem({
super.key,
required this.title,
required this.leadingIcon,
required this.press,
});
#override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(leadingIcon),
title: Text(title),
onTap: press,
);
}
}
class DashboardScreen extends StatelessWidget {
const DashboardScreen({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.red,
child: Center(child: Text('Dashboard screen')),
),
);
}
}
class UserScreen extends StatelessWidget {
const UserScreen({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.blue,
child: Center(child: Text('User screen')),
),
);
}
}

Passing Arguments between pages but show this error

I m trying to pass arguments between pages but I m getting this error:
FlutterError (Could not find a generator for route RouteSettings("detail", Instance of 'Commodity') in the _WidgetsAppState.
Make sure your root app widget has provided a way to generate
this route.
Generators for routes are searched for in the following order:
For the "/" route, the "home" property, if non-null, is used.
Otherwise, the "routes" table is used, if it has an entry for the route.
Otherwise, onGenerateRoute is called. It should return a non-null value for any valid route not handled by "home" and "routes".
Finally if all else fails onUnknownRoute is called.
Unfortunately, onUnknownRoute was not set.)
I don't know why because 'detail' page already setted
This is my Main App
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: WelcomePage.routeName,
routes: {
'/welcome': (_) => const WelcomePage(),
'detail': (_) => SubCommoditiePage(),
},
);
}
}
This is my From Page
class DisplayOptions extends StatelessWidget {
final List<Commodity> _optionsToDisplay;
const DisplayOptions(this._optionsToDisplay);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _optionsToDisplay.length,
itemBuilder: (context, index) {
final opt = _optionsToDisplay[index];
return ListTile(
title: Text(opt.label),
subtitle: Text(opt.shortLabel),
onTap: () {
Navigator.pushNamed(context, 'detail', arguments: _optionsToDisplay[index]);
});
});
}
}
This is my Destination Page
class SubCommoditiePage extends StatefulWidget {
const SubCommoditiePage({Key? key}) : super(key: key);
static const String routenName = 'detail';
static Route route() {
return MaterialPageRoute(
builder: (_) => const SubCommoditiePage(),
settings: const RouteSettings(name: routenName));
}
#override
_SubCommoditiePageState createState() => _SubCommoditiePageState();
}
class _SubCommoditiePageState extends State<SubCommoditiePage> {
#override
Widget build(BuildContext context) {
final Commodity commoditySeleted =
ModalRoute.of(context)?.settings.arguments as Commodity;
return Scaffold(
appBar: AppBar(
title: Text(commoditySeleted.label),
),
);
}
}
For initial/homepage, use /. In this case your WelcomePage.routeName will be /;
and route
routes: {
WelcomePage.routeName: (_) => WelcomePage(),
..........
},
You don't need to pass initialRoute while the root '/' will be selected.
For more about named-routes
The way I was able to solve it was:
I evidently didn't know why flutter didn't recognize my 'detail' page.
And I had to do it this way:
This is my From Page
in my ontap, I used
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SubCommoditiePage(
seleted: _optionsToDisplay[index],
)));
like that:
class DisplayOptions extends StatelessWidget {
final List<Commodity> _optionsToDisplay;
const DisplayOptions(this._optionsToDisplay);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _optionsToDisplay.length,
itemBuilder: (context, index) {
final opt = _optionsToDisplay[index];
return ListTile(
title: Text(opt.label),
subtitle: Text(opt.shortLabel),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SubCommoditiePage(
seleted: _optionsToDisplay[index],
)));
});
});
}
}
adding to my page: final Commodity seleted; and with widget.selected... I was able to use it perfectly!
class SubCommoditiePage extends StatefulWidget {
final Commodity seleted;
const SubCommoditiePage({required this.seleted, Key? key}) : super(key: key);
static const String routenName = 'detail';
#override
_SubCommoditiePageState createState() => _SubCommoditiePageState();
}
class _SubCommoditiePageState extends State<SubCommoditiePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.seleted.label),
backgroundColor: const Color.fromRGBO(37, 59, 128, 5),
),
body: ListView.builder(
itemCount: widget.seleted.subCommodities.length,
itemBuilder: (context, index) {
final opt = widget.seleted.subCommodities[index];
return ListTile(
title: Text(opt.label),
onTap: () {},
);
}));
}
}

Flutter passed arguments return null allways

In this simple flutter GitHub repository implementation we have a simple screen which we want to pass arguments and getting them in destination screen, for example
form ScreenA() we want pass arguments to ScreenB()
defined routes:
routes: {
'/page/one': (context) => ScreenA(),
'/page/two': (context) => ScreenB(),
'/page/three': (context) => ScreenC(),
},
fist of all we have ScreenA():
class ScreenA extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Navigation with params'),
),
body: Center(
child: ElevatedButton(
child: Text('Click me!'),
onPressed: () {
Navigator.pushNamed(
context,
'/page/two',
arguments: PageArguments(
id: 1,
title: "Example Title"
),
);
},
),
),
);
}
}
and destination page as ScreenB() is:
class ScreenB extends StatelessWidget {
#override
Widget build(BuildContext context) {
final arguments = ModalRoute.of(context)!.settings.arguments;
/* getting currect route name */
print(ModalRoute.of(context)!.settings.name);
/* getting NULL arguments */
print(arguments);
return Scaffold();
}
}
class PageArguments{
final int id;
final String title;
PageArguments({required this.id, required this.title});
}
It seems that Persistent Bottom Navigation Bar package does not pass correctly route information, it could be a bug. If you put a breakpoint in the build method of ScreenB, you will see that not only the argument is null, but route name is also wrong.
I tried in main.dart with onGenerateRoute and it worked for me this way:
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
title: 'Home',
icon: Icon(Icons.home),
routeAndNavigatorSettings: RouteAndNavigatorSettings(
initialRoute: '/page/one',
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
// Manage your route names here
switch (settings.name) {
case '/page/one':
builder = (BuildContext context) => ScreenA();
break;
case '/page/two':
builder = (BuildContext context) => ScreenB();
break;
default:
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute(
builder: builder,
settings: settings,
);
})),
PersistentBottomNavBarItem(title: 'Help', icon: Icon(Icons.help)),
];
}
About casting the argument, I agree with the other answer.
Main and MyApp for reference
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ScreenA(),
routes: {
'/page/one': (context) => ScreenA(),
'/page/two': (context) => ScreenB(),
},
);
}
}
Update ClassB with below code no modification required in ClassA
class ScreenB extends StatelessWidget {
#override
Widget build(BuildContext context) {
final arguments =
ModalRoute.of(context)!.settings.arguments as PageArguments;
print(ModalRoute.of(context)!.settings.name);
print(arguments.id);
print(arguments.title);
print("------");
return Scaffold();
}
}
Key update:
Typecasting the argument.
final arguments =
ModalRoute.of(context)!.settings.arguments as PageArguments;
Console log:

Why my Flutter Scaffold back button always return to root?

If I have stacks of screens: A -> B -> C, whethen I press back button on the simulator or press back button on the Scaffold's back button on C, I always returned to A, not B. Why? And how to fix it? I searched on the
Here's how I push and pop. These code are simplified to only show the push/pop and screen build functions.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: UserListPage()
);
}
}
class UserListPage extends StatefulWidget {
#override
_UserListPageState createState() => _UserListPageState();
}
class _UserListPageState extends State<UserListPage> {
...
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("User list")),
body: Builder(builder: (context) {
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SessionListPage(userId: users[index].id)
),
child: ...
})
}),
);
}
...
}
class SessionListPage extends StatefulWidget {
final int userId;
SessionListPage({ this.userId }) : super();
#override
_SessionListPageState createState() => _SessionListPageState();
}
class _SessionListPageState extends State<SessionListPage> {
...
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Session list")),
body: Builder(builder: (context) {
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DrawingPage(userId: widget.userId, sessionId: sessions[index].id)
),
child: ...
})
}),
);
}
...
}
class DrawingPage extends StatefulWidget {
final int userId;
final int sessionId;
DrawingPage({ this.userId, this.sessionId }) : super();
#override
_State createState() => _State();
}
class _State extends State<DrawingPage> {
#override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text("Enter the Number")),
body: Builder(builder: (context) {
InkWell(
onTap: () { Navigator.pop(context); } // here it returns straight to UserListPage instead of SessionListPage
child: ...
})
}
));
}
}
One thing that I noticed is that for the context that was supplied to push and pop, is from Builder instead of the context supplied from Widget build function. Does it have any impact?
Please remove super(); from all places.
Young, It's working fine. Please check below link
Code

Bottom tab navigator show up when I click back button from my phone in flutter

Hi I am new in flutter and right now I try to declare my data for all tabs with this code, but when I click tab, the bottom navigator is dismiss and show up again when I click back button from my phone, is there anyone know the mistakes or the problems?
class BottomTab extends StatefulWidget {
final String text;
BottomTab({this.text});
#override
_BottomTabState createState() => _BottomTabState();
}
class _BottomTabState extends State<BottomTab> {
void initState() {
super.initState();
}
_onTap(int index) {
setState(() => _selectedIndex = index);
if (index == 0) {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new HomeScreen(value: widget.value)));
} else if (index == 1) {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new FirstPage(value: widget.value)));
} else {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new HomeScreen(value: widget.value)));
}
}
final List<Widget> pages = [
HomeScreen(),
FirstPage(),
];
final PageStorageBucket bucket = PageStorageBucket();
int _index = 0;
Widget _myList(int index) => BottomNavigationBar(
onTap: _onTap,
currentIndex: index,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(icon: Icon(Icons.more), title: Text('More')),
],
);
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: _myList(_index),
body: PageStorage(
child: pages[_index],
bucket: bucket,
),
);
}
}
You can copy paste run full code below
In your case, you do not need Navigator.push and change this line
From
setState(() => _selectedIndex = index);
To
setState(() => _index = index);
working demo
full code
import 'package:flutter/material.dart';
class BottomTab extends StatefulWidget {
final String text;
BottomTab({this.text});
#override
_BottomTabState createState() => _BottomTabState();
}
class _BottomTabState extends State<BottomTab> {
void initState() {
super.initState();
}
_onTap(int index) {
setState(() => _index = index);
/*if (index == 0) {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new HomeScreen(value: widget.value)));
} else if (index == 1) {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new FirstPage(value: widget.value)));
} else {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new HomeScreen(value: widget.value)));
}*/
}
final List<Widget> pages = [
HomeScreen(),
FirstPage(),
];
final PageStorageBucket bucket = PageStorageBucket();
int _index = 0;
Widget _myList(int index) => BottomNavigationBar(
onTap: _onTap,
currentIndex: index,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(icon: Icon(Icons.more), title: Text('More')),
],
);
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: _myList(_index),
body: PageStorage(
child: pages[_index],
bucket: bucket,
),
);
}
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("demo"),
),
body: Text("HomesScreen"));
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("demo"),
),
body: Text("FirstPage"));
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BottomTab(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}