/*This is my code
On the main page:
*/
home: MyHomePage(),
routes: <String, WidgetBuilder> {
'/screen1': (BuildContext context) => new NewCreateProfile()
},
// Want to come on this page with Results
Navigator.of(context).popUntil((route) => route.isFirst );
Define final variable in first screen use required
Set the value of results to a variable by setstate
Navigator.push( context,MaterialPageRoute(
builder: (context) => firstscreen(result),
),
);
Related
I am trying to provide a local bloc to a new page, I found some way to do this by using an anonymous route but it doesn't look elegant
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return BlocProvider.value(
value: context.bloc<MyBloc>(),
child: NewPage());
}),
);
What I want is to do the same thing but using a named route and without creating a global bloc as I simply can't
Create app_router.dart file.
app_router.dart
class AppRouter {
final LocalBloc _localBloc = LocalBloc();
Route onGenerateRoute(RouteSettings routeSettings) {
switch (routeSettings.name) {
case '/':
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _localBloc,
child: Home(),
),
);
case '/page1':
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _localBloc,
child: Page1(),
),
);
case '/page2':
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _localBloc,
child: Pag2(),
),
);
}
}
}
Then in your main.dart file
Add onGenerateRoute
final AppRouter _appRouter = AppRouter();
MaterialApp(
title: 'My App',
onGenerateRoute: _appRouter.onGenerateRoute,
),),
In your navigation, you can do this:
Navigator.of(context).pushNamed('/page1');
I am struggling in my app:
After the user logs in I navigate to my HomeView with pushReplaceNamed , so the user should not be able to pop (by dragging) on the HomeView because in my thought it is the root view. However that is not the case.. Even after calling pushReplaceNamed the user can still drag to pop:
I simply call:
Navigator.pushReplacementNamed(
context,
Views.home,
);
On the first start of the App StartView is displayed, from there I navigate to EmailView and from there to LoginView. The code above is inside my LoginView. In all the other views I simply call pushNamed.
What am I missing here? Why can the user drag pop on HomeView?
(I know I can disable it with WillPopScope, but that does not feel right...)
This is my setup in my MaterialApp:
Widget build(BuildContext context) {
return MaterialApp(
title: 'AppFlug',
navigatorKey: Get.key,
theme: ThemeData(
fontFamily: AppTextStyles.montserrat,
primarySwatch: ColorService.createMaterialColor(
AppColors.blue,
),
backgroundColor: AppColors.white,
scaffoldBackgroundColor: AppColors.white,
),
initialRoute:
AuthenticationService.isLoggedIn() ? Views.home : Views.start,
onGenerateRoute: AppRouter.generateRoute,
);
}
And here is my AppRouter:
class AppRouter {
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case Views.start:
return MaterialPageRoute(
builder: (context) => const StartView(),
);
case Views.email:
return MaterialPageRoute(
builder: (context) => EmailView(),
);
case Views.signUp:
String email = settings.arguments as String;
return MaterialPageRoute(
builder: (context) => SignUpView(
email: email,
),
);
case Views.login:
String email = settings.arguments as String;
return MaterialPageRoute(
builder: (context) => LoginView(
email: email,
),
);
case Views.home:
return MaterialPageRoute(
builder: (context) => HomeView(),
);
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
body: Center(
child: Text(
'No route defined for ${settings.name}',
),
),
),
);
}
}
}
In your scenario, the user will be able to drag to pop and will return to EmailView cause you replaced login with home, this is what happens right? if u want to pop all of them (StartView, EmailView, LoginView) when you push to HomeView, then use:
Navigator.pushNamedAndRemoveUntil(context, Views.Home, (route) => route.settings.name == '/')
Also, add this to your AppRouter Cases
MaterialPageRoute(
settings: RouteSettings(name: /*name of the route*/),
builder: (context) => ...
With the help of Omar I got it working: so pushReplaceNamed is only replacing the top most route. In my case all I had to do was call:
Navigator.pushNamedAndRemoveUntil(
context,
Views.home,
(route) => false,
);
To quote the doc:
To remove all the routes below the pushed route, use a [RoutePredicate] that always returns false (e.g. (Route route) => false).
Let's consider we have a list of pages and based on some logic, we want to display the corresponding route using Navigator. How do we do that?
final List<dynamic> components = [ PageA, PageB ]
..
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => new components[0]()),
);
There is routes attribute within material app widget. You should use that:
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Sample',
home: Wrapper(),
routes: {
CarsList.routeName: (ctx) => PageOne(),
CarDisplay.routeName: (ctx) => PageTwo(),
OrdersScreen.routeName: (ctx) => PageThree(),
EditCar.routeName: (ctx) => PageFour(),
},
),
Before using that make sure that you have a static variable named as routeName in every widget.
static const routeName = '/PageOne';
I'm not entirely sure I understand you issuer but if your question is where/how you can put a condition there are two ways of doing so:
Let's say that based on condition you when to navigate to either components[0]() or components[1]() :
First:
final List<dynamic> components = [ PageA, PageB ]
..
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => condition ? new components[0]() : new component[1]()
),
);
Second:
final List<dynamic> components = [ PageA, PageB ]
..
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
if (condition) {
return new components[0]()
} else {
return new component[1]()
}
),
);
Dears,
I am using provider dart package which allows listeners to get notified on changes to models per se.
I am able to detect the change inside my main app root tree, and also able to change the string value of initial route however my screen is not updating. Kindly see below the code snippet and the comments lines:
void main() => runApp(_MyAppMain());
class _MyAppMain extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<UserProvider>.value(
value: UserProvider(),
),
ChangeNotifierProvider<PhoneProvider>.value(
value: PhoneProvider(),
)
],
child: Consumer<UserProvider>(
builder: (BuildContext context, userProvider, _) {
return FutureBuilder(
future: userProvider.getUser(),
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
final User user = snapshot.data;
String initialScreen = LoginScreen.path;
// (1) I am able to get into the condition
if (user.hasActiveLogin()) {
initialScreen = HomeOneScreen.path;
}
return MaterialApp(
title: 'MyApp',
theme: ThemeData(
primarySwatch: Colors.green,
accentColor: Colors.blueGrey,
),
initialRoute: initialScreen,
// (2) here the screen is not changing...?
routes: {
'/': (context) => null,
LoginScreen.path: (context) => LoginScreen(),
RegisterScreen.path: (context) => RegisterScreen(),
HomeOneScreen.path: (context) => HomeOneScreen(),
HomeTwoScreen.path: (context) => HomeTwoScreen(),
RegisterPhoneScreen.path: (context) => RegisterPhoneScreen(),
VerifyPhoneScreen.path: (context) => VerifyPhoneScreen(),
},
);
},
);
},
),
);
}
}
Kindly Note the Below:
These are are paths static const strings
LoginScreen.path = "login"
RegisterScreen.path = "/register-screen"
HomeOneScreen.path = "home-one-screen"
HomeTwoScreen.path = "home-two-screen"
RegisterPhoneScreen.path = "/register-phone-screen"
VerifyPhoneScreen.path = "/verify-phone-screen"
What I am missing for dynamic initialRoute to work?
Many Thanks
According to this issue described on github issues it is not permissible to have initial route changes. At least this is what I understood. However what I did is that I replaced the initialRoute attribute with home attr. Thus this change mandates that initialScreen becomes a widget var.
The changes is shown below:
void main() => runApp(_MyAppMain());
class _MyAppMain extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<UserProvider>.value(
value: UserProvider(),
),
ChangeNotifierProvider<PhoneProvider>.value(
value: PhoneProvider(),
)
],
child: Consumer<UserProvider>(
builder: (BuildContext context, userProvider, _) {
return FutureBuilder(
future: userProvider.getUser(),
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
final User user = snapshot.data;
// (1) This becomes a widget
Widget initialScreen = LoginScreen();
if (user.hasActiveLogin()) {
initialScreen = HomeOneScreen();
}
return MaterialApp(
title: 'MyApp',
theme: ThemeData(
primarySwatch: Colors.green,
accentColor: Colors.blueGrey,
),
home: initialScreen,
// (2) here the initial route becomes home attr.
routes: {
'/': (context) => null,
LoginScreen.path: (context) => LoginScreen(),
RegisterScreen.path: (context) => RegisterScreen(),
HomeOneScreen.path: (context) => HomeOneScreen(),
HomeTwoScreen.path: (context) => HomeTwoScreen(),
RegisterPhoneScreen.path: (context) => RegisterPhoneScreen(),
VerifyPhoneScreen.path: (context) => VerifyPhoneScreen(),
},
);
},
);
},
),
);
}
}
Also note on my RegistrationScreen on success api response I did Navigator.of(context).pop()
Thanks
First of all, I'm not setting my routs in the MaterialApp like this
new MaterialApp(
home: new Screen1(),
routes: <String, WidgetBuilder> {
'/screen1': (BuildContext context) => new Screen1(),
'/screen2' : (BuildContext context) => new Screen2(),
'/screen3' : (BuildContext context) => new Screen3(),
'/screen4' : (BuildContext context) => new Screen4()
},
)
Instead, I'm routing from different places in my app by pushing new rout like this:
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
Screen3(someInputData)));
How I can pop screens from the current one into screen number 2 for example?
Asumming: Screen1 -> Screen2 -> Screen3 -> Screen4
When you open the Screen2 , you could do something like this:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Screen2(),
settings: RouteSettings(name: '/screen2')),
);
And when you want to go back from Screen4 to Screen2 :
Navigator.popUntil(context, ModalRoute.withName("/screen2"));
If you just want to go back to the previous screen use:
Navigator.of(context).pop();