I am trying switch to a different screen in Flutter project using onPressed but it is not generating any outcome not sure what is the reason.
Here is the homescreen page:
onPressed: () {
const User_Profile();
print("Hello");
},
Here is the user profile:
class User_Profile extends StatefulWidget {
const User_Profile({Key? key}) : super(key: key);
#override
State<User_Profile> createState() => _user_profileState();
}
class _user_profileState extends State<User_Profile> {
#override
Widget build(BuildContext context) {
return const Text("User Profile");
}
}
Question:
How to switch screens using Onpressed? What am I doing wrong noting that the word Hello for debugging is printed everytime.
Try below code and use Navigator.push refer navigation
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => User_Profile(),
),
);
},
child: const Text('User Profile'),
),
You have to use a function instead of your class like this:
Navigator.push(context, MaterialPageRoute(builder: (context)=>User_profile()));
call this:
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context)=>User_profile()));
},
instead of this:
onPressed: () {
const User_Profile();
print("Hello");
},
as you know you can't go to a specific page by calling the constructor method in a class. you have 2 ways:
use Navigator.push like this:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => User_Profile(),
),
);
and you can send the parameters to the next page by sending by constructor parameters like: User_Profile(name: 'yourName').2) you can use Navigator.pushNamed. you can define routeName in your main class of the project like this:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(
MyApp(),
);
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
canvasColor: Colors.transparent,
),
initialRoute: '/',
routes: {
'/': (context) => Splash(),
'/user_profile': (context) => User_Profile(),
},
);
}
}
as you see you defined a routeName '/user_profile' and you can use Navigator.pushNamed and if you want to pass parameters to the next page you have to use arguments like this:
Navigator.pushNamed(
context,
'/user_profile',
arguments: {"name" : "yourName"},);
and this code is for getting the arguments that you've passed in your User_Profile :
var arguments = ModalRoute.of(context)!.settings.arguments as Map;
var name = arguments['name'] as String;
I recommend you to use the second way to know all your routes of your projects.
Good Luck;)
Related
I want to parse arguments with Navigator.push() to my other dart file .
Because I want to send the path of the selected song in songlist,
to the music player main UI (For Playing)
[ songlist.dart ]
child:ListView.builder(
itemCount: getSongList()[0].length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(getSongList()[1][index].split('/').last,style:
const TextStyle(
fontSize: 21
),),
leading: IconButton(onPressed: (){
Navigator.push(context,MaterialPageRoute(builder: (context) => music_player()));
},
icon: Icon(Icons.my_library_music)),
);
}
)
),
[ musicplayer.dart ]
class music_player extends StatefulWidget {
const music_player({Key? key}) : super(key: key);
#override
State<music_player> createState() => _music_playerState();
}
class _music_playerState extends State<music_player> {
// codes
}
Just wanna know how to parse arguments from my first file to second file.
If I pass arguments there will be an error :
too many positional arguments: 0 expected, but 1 found.
Thanks in advance.
you need to add parameter(selectedSongs) in widget like this:
class MusicPlayer extends StatefulWidget {
final selectedSongs;
const MusicPlayer({
Key? key,
this.selectedSongs,
}) : super(key: key);
#override
State<MusicPlayer> createState() => _MusicPlayerState();
}
class _MusicPlayerState extends State<MusicPlayer> {
#override
Widget build(BuildContext context) {
return const Placeholder();
}
}
this way you can use in Navigator.push:
Navigator.push(context,MaterialPageRoute(builder: (context) => MusicPlayer(selectedSongs: selectedsongList,))));
If your want to pass arguments with Navigator the correct way is:
-Register the widget in the routes:
MaterialApp(
routes: {
ExtractArgumentsScreen.routeName: (context) =>
const ExtractArgumentsScreen(),
},
)
-Navigate to the widget:
Navigator.pushNamed(
context,
ExtractArgumentsScreen.routeName,
arguments: // whatever you want to pass,
);
And inside your next page widget:
#override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments;
return Scafold( ... );
}
All information here: https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments
I'm Working on Project Where there is A screen For viewing the user Profile and another screen for Editing Profile. I'm using onGenerateRoute Method for Routing and know I can parse an argument and send it over.
How I can use Call Back Function ValueChange with onGenerateRoute Method?
Navigate to the EditingProfile Page and pass the Function as an argument:
Navigator.pushNamed(context, "/editingprofile", arguments: () {
print("Function called");
});
In the onGenerateRoute pass the argument to the EditingProfile either as constructor param and call the variable directly
Route<dynamic>? generateRoute(RouteSettings settings) {
final args = settings.arguments;
switch (settings.name) {
case "/editingprofile":
return MaterialPageRoute(
builder: (context) => EditingPage(settings.arguments as Function));
}
}
class EditingPage extends StatelessWidget {
Function callback;
SecondPage(this.callback, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: OutlinedButton(
onPressed: (){
callback.call();
},
child: Text("Press me"),
),
);
}
}
or pass it inside the MaterialPageRoute as settings param and get the function with ModalRoute
Route<dynamic>? generateRoute(RouteSettings settings) {
final args = settings.arguments;
switch (settings.name) {
case "/editingprofile":
return MaterialPageRoute(
settings: settings,
builder: (context) => EditingProfile());
}
}
class EditingPage extends StatelessWidget {
EditingPage ({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Function callback = ModalRoute.of(context)!.settings.arguments as Function;
return Scaffold(
body: OutlinedButton(
onPressed: (){
callback.call();
},
child: Text("Press me"),
),
);
}
}
I'm new in flutter and trying to understand flutter state management concept using provider. This the image scenario what I'm trying to do
I have created a file called auth_provider.dart file under the folder called Providers
class AuthProvider with ChangeNotifier{
bool isLogin = false;
Future createUser() async
{
isLogin = true;
notifyListeners();
}
Future login() async
{
isLogin = true;
notifyListeners();
}
void logout()
{
isLogin = false;
notifyListeners();
}
}
This the Signup button that I have created in the login page
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SignupPage()
),
);
},
child: const Text(
'Signup Button',
),
)
This is the signUp button in signup screen
child: ElevatedButton(
onPressed: () => signUpSubmit(),
child: const Text(
'Sign Up',
),
),
I have written a signUpSubmit future like below
Future<void> signUpSubmit() async {
Provider.of<AuthProvider>(context, listen: false).createUser();
}
I have used AuthProvider consumer in main.dart page
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => AuthProvider(),
),
],
child: Consumer<AuthProvider>(
builder: (ctx,auth,child){
print(auth.isLogin);
return MaterialApp(
home: auth.isLogin ? const HomeScreen():const LoginPage(),
routes: {
HomeScreen.routeName: (ctx) => const HomeScreen(),
SignupPage.routeName: (ctx) => const SignupPage(),
LoginPage.routeName: (ctx) => const LoginPage(),
},
);
}
),
);
}
}
After click on signup button I'm getting true in main page , which I have given a print under Consumer builder in main.dart page. So according to MaterialApp widget home condition page should redirect to HomeScreen but it's not moving. Why it's not moving ? What is the main cause and what it the best way to solve this problem ?
Note : If I try it from login screen redirection is working fine. But according to my image flow (Login -> signup) it's not working.
here is the code you are looking for, but bear in mind with the implementation you have right now, if the user opens the app again, it will redirect them to the signin page. because the boolean value will disappear once the user closes the app.
change your main.dart file like the following..
main function
void main() {
// you just need to add the multiprovider and the change notifier provider class
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AuthProvider()),
],
child: const MyApp(),
),
);
}
here is the MyApp class as i understand it.
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 Consumer<AuthProvider>(builder: (ctx, auth, child) {
print(auth.isLogin);
return MaterialApp(
home: auth.isLogin ? MyHomePage() : LoginPage(),
routes: {
MyHomePage.routeName: (ctx) => MyHomePage(),
LoginPage.routeName: (ctx) => LoginPage(),
//NavScreen.routeName: (ctx) => const NavScreen(),
},
);
});
}
}
Change the signup button in the register page to the following.
ElevatedButton(
onPressed: () {
signUpSubmit(context);
Navigator.of(context).pushNamed(HomeScreen.routeName);
},
and the signupsubmit function like this..
signUpSubmit(BuildContext context) {
Provider.of<AuthProvider>(context, listen: false).createUser();
}
The main cause of your problem is that you are pushing a new route (screen) from login page and the best way to solve problem is to pop that route (screen) from sigupPage.
On click of Signup button from login page you are pushing a new route, so in order to redirect to HomeScreen from SignupPage first you need to pop that route so that you can see the updated changes.
Future<void> signUpSubmit() async {
Navigator.of(context).pop();
Provider.of<AuthProvider>(context, listen: false).createUser();
}
https://docs.flutter.dev/cookbook/navigation/navigation-basics
My final goal is to have a userName variable from one dart file transferred to the other dart file.
Firebase Authentication will only take the email and password inputs so I need to pass the userName variable as an argument into another file that is called after the users email has been verified.
I have been trying to find videos and documentation online, most of what I found is trying to put the data into a list (which I would like to avoid). I don't understand the "this." getter function in flutter yet, I don't know if it's necessary to solve this problem. Let me know if there's anything I can clarify, I hope I'm overlooking something simple.
Dart File #1
onPressed: () => signUp(_email, _password).then((_) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => Verify(_userName)));
}),
Dart File #2
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class Verify extends StatefulWidget {
const Verify(String _userName, {Key? key}) : super(key: key);
#override
_VerifyState createState() => _VerifyState();
}
class _VerifyState extends State<Verify> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
Text('Here is your variable $_userName please verify'),
),
);
}
I guess you're asking about passing arguments(any object) between different screens.
You can do this easily by passing it in RouteSettings, you can pass any object (String, int, map) and then fetch it in the build method of another Screen.
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return TextButton(
onPressed: () => Navigator.push(
context, MaterialPageRoute(
builder: (context) => HomeScreen(),
settings: const RouteSettings(arguments: 'username')),), //arguments
child: Text('Hello, World!',
style: Theme.of(context).textTheme.headline4,
),
);
}
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as String; //arguments
return TextButton(
onPressed: () {},
child: Text(args,
style: Theme.of(context).textTheme.headline4,
),
);
}
}
I have been looking at all the answers on here to pass arguments when doing named route navigation but they seem to be old answers or they don't work.
From what was written it should be working but it doesn't seem to do anything, so I am not sure where my error is.
This is how I have it setup:
Main.dart (With my named routes setup):
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Colors.white,
),
initialRoute: HomePageScreen.id,
routes: {
HomePageScreen.id: (context) => HomePageScreen(),
AddItemScreen.id: (context) => AddItemScreen(),
AdvertiseScreen.id: (context) => AdvertiseScreen(),
HomePageFilterScreen.id: (context) => HomePageFilterScreen(),
HomePageResultsScreen.id: (context) => HomePageResultsScreen(),
ItemPageProfileScreen.id: (context) => ItemPageProfileScreen(),
ItemPageProfileSuggestUpdateScreen.id: (context) => ItemPageProfileSuggestUpdateScreen(),
ItemPageWhereToBuyAddStoreToDatabaseScreen.id: (context) => ItemPageWhereToBuyAddStoreToDatabaseScreen(),
ItemPageWhereToBuyMapScreen.id: (context) => ItemPageWhereToBuyMapScreen(),
ItemPageWhereToBuyScreen.id: (context) => ItemPageWhereToBuyScreen(),
MenuScreen.id: (context) => MenuScreen(),
NotAvailableScreen.id: (context) => NotAvailableScreen(),
TermsScreen.id: (context) => TermsScreen(),
}
);
}
}
HomePageResultsScreen.dart (On button click I am using push named to navigate to the next page, this is working because the new page 'ItemPageProfileScreen is opening):
onTap: () {
Navigator.pushNamed(context, ItemPageProfileScreen.id, arguments: 'MyTestString');
}
ItemPageProfileScreen.dart (I have tried using MaterialApp onGenerateRoute to get the arguments and print to screen to test but it is not working):
class ItemPageProfileScreen extends StatefulWidget {
static const String id = 'item_page_profile_screen';
#override
_ItemPageProfileScreenState createState() => _ItemPageProfileScreenState();
}
class _ItemPageProfileScreenState extends State<ItemPageProfileScreen> {
#override
Widget build(BuildContext context) {
MaterialApp(
onGenerateRoute: (routeSettings){
final arguments = routeSettings.arguments;
print(arguments.toString());
},
);
return Scaffold(),
Thanks for your help.
EDIT Second attempt:
class ItemPageProfileScreen extends StatefulWidget {
final String argument;
ItemPageProfileScreen(this.argument);
static const String id = 'item_page_profile_screen';
#override
_ItemPageProfileScreenState createState() => _ItemPageProfileScreenState();
}
class _ItemPageProfileScreenState extends State<ItemPageProfileScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Text(widget.argument),
There is an official article on how to pass arguments with named routing. https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments
The main idea is pretty straightforward: pass arguments into the constructor of your screen widget.
In the official docs (in the link above) they actually used both approaches with named routing and with regular routing even though the article stated about named routing.
Anyways. Focus on the constructor and arguments.
Where can you access the constructor of your screen with named routing if you pass only the name of the route when you navigate? In onGenerateRoute method. Let's do it.
Overwrite onGenerateRoute method in your top screen MyApp (that's where your mistake was). And if you do it you don't need routes: {} there (your second mistake)
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Colors.white,
),
initialRoute: HomePageScreen.id,
onGenerateRoute: (settings) {
if(settings.name == ItemPageProfileScreen.id) {
String msg = settings.arguments;
return MaterialPageRoute(builder: (_) => ItemPageProfileScreen(msg));
} else if(...
},
Get the arguments from the widget constructor:
class ItemPageProfileScreen extends StatefulWidget {
final String argument;
ItemPageProfileScreen(this.argument);
static const String id = 'item_page_profile_screen';
#override
_ItemPageProfileScreenState createState() => _ItemPageProfileScreenState();
}
class _ItemPageProfileScreenState extends State<ItemPageProfileScreen> {
#override
Widget build(BuildContext context) {
String msg = widget.argument;
...
And sending arguments over on tap:
onTap: () {Navigator.pushNamed(context, ItemPageProfileScreen.id, arguments: 'MyTestString');}
Hope this helps.