Flutter passed arguments return null allways - flutter

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:

Related

How to pass arguments to pushReplacementNamed?

In my application, when the 'Next' button is clicked, pushReplacementNamed is fired and the arguments are passed to the next screen. How can I implement a route with arguments? Need exactly pushReplacementNamed.
Here is an example code with push:
_changeColor(String color) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ColorWidget(color: color),
),
);
}
...
ElevatedButton(
onPressed: () => _changeColor(selectedValue),
child: const Text('Next'),
)
How can one also pass arguments with pushReplacementNamed?
My main.dart:
void main() {
runApp(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.blue,
),
routes: {
'/': (context) => HomeScreenWidget(),
'/color_picker': (context) => ColorPickerWidget(),
'/text_value': (context) => TextValueScreen(),
},
initialRoute: '/',
);
}
}
You have to send data in arguments key and get it back by route.
Check this document https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments
Simply use
var argument = 'example string';
Navigator.pushNamed(
context,
'/otherscreen',
arguments: {'exampleArgument': argument},
);
and extract the arguments as follows:
#override
Widget build(BuildContext context) {
final arguments = (ModalRoute.of(context)?.settings.arguments ?? <String, dynamic>{}) as Map;
print(arguments['exampleArgument']);
return Scaffold(...);

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

Flutter "context " Navigatior.pushedNamed generator RouteSettings

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(),
},
));

How make button which open random page in Flutter?

This is my first post, so sorry for errors. I have a problem I can't make a button which open radom page in my apk. The project is connected with Coronavirus.
You can easily use RouteGenerator and list with needed random pages for this task.
main.dart:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Random pages',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: 'start_page',
onGenerateRoute: RouteGenerator.generateRoute,
);
}
}
route_generator.dart:
class RouteGenerator {
static List<String> myRandomPages = [
'first_page',
'second_page'
];
static String getRandomNameOfRoute(){
return myRandomPages[Random().nextInt(myRandomPages.length)];
}
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case 'start_page':
return MaterialPageRoute(builder: (_) => StartPage());
case 'first_page':
return MaterialPageRoute(builder: (_) => FirstPage()); // FirstPage - is just a Widget with your content
case 'second_page':
return MaterialPageRoute(builder: (_) => SecondPage());// Also custom Widget
//... other random or not pages
}
}
}
start_page.dart:
class StartPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Start page'),
),
body: Center(
child: RaisedButton(
child: Text('Go to random page'),
onPressed: () => Navigator.of(context).pushNamed(RouteGenerator.getRandomNameOfRoute()),
),
)
);
}
}

Cannot find the 'arguments' in Navigator.pushNamed when pushing to next screen

I am trying to move signup screen to OTP screen. From Signup screen I need to pass email id to OTP screen. Now, I am using below, but cannot resolve the arguments: parameter in that.
Navigator.pushNamed(context, Routes.ROUTE_OTP,arguments:{"id": 'email'});
Searched so many tutorials they given there to use arguments:( but my bad I can't find:(
A simple example demonstrating your requirement follows:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
onGenerateRoute: (settings) {
WidgetBuilder builder;
Map arguments = settings.arguments;
switch (settings.name) {
case '/':
builder = (
BuildContext _,
) =>
SignUp();
break;
case '/otp':
builder = (
BuildContext _,
) =>
Otp(id: arguments["id"]);
break;
default:
return null;
}
return MaterialPageRoute(builder: builder, settings: settings);
},
);
}
}
class SignUp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Signup"),
),
body: Center(
child: FlatButton(
onPressed: () {
Navigator.of(context).pushNamed(
"/otp",
arguments: {
"id": "email#email.com",
},
);
},
child: Text("SEND OTP")),
),
);
}
}
class Otp extends StatelessWidget {
final String id;
Otp({this.id});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("OTP"),
),
body: Center(
child: Text(id),
),
);
}
}