I found some answers about this [here, here] but none of them completely answer my question.
I'm going to be using the package provider to describe my question because it greatly reduces the boilerplate code.
What I want to do is to inject a dependency when (and only when) a route is called. I can achieve that by doing something like this on onGenerateRoute:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Routes Demo',
initialRoute: '/',
onGenerateRoute: (settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(builder: (_) => HomePage());
case '/firstPage':
return MaterialPageRoute(
builder: (_) => Provider(
builder: (_) => MyComplexClass(),
child: FirstPage(),
),
);
case '/secondPage':
return MaterialPageRoute(builder: (_) => SecondPage());
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
body: Center(
child: Text('Route does not exists'),
),
),
);
}
});
}
}
class MyComplexClass {
String message = 'UUUH I am so complex';
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RaisedButton(
child: Text('Go to first page'),
onPressed: () {
Navigator.pushNamed(context, '/firstPage');
}),
],
),
));
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final myComplexClass = Provider.of<MyComplexClass>(context);
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Center(
child: Text(myComplexClass.message),
),
RaisedButton(
child: Text('Go to second page'),
onPressed: () {
Navigator.pushNamed(context, '/secondPage');
},
)
],
),
),
);
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final myComplexClass = Provider.of<MyComplexClass>(context);
return Scaffold(
body: Center(
child: Text(myComplexClass.message),
),
);
}
}
This works fine for '/firstPage', but as soon as I push another route from inside 'firstPage' the context is lost and I loose access to MyComplexClass, since the navigator stays at the top of the tree together with MaterialApp the next route will loose the context where MyComplexClass was injected, I cannot manage to find a elegant solution to this.
This is the navigator stack we end up with:
As we can see SecondPage is not a child of Provider, hence the problem.
I don't want to inject all dependencies I have all at once on top of MainApp, I want to inject them as they're needed.
I considered creating new navigators each time I need another "fold", but that seems to become really messy very quickly.
How do I solve this issue?
In the following examples, both the route / and /login can access Provider.of<int>, but the route /other can't.
There are two solutions:
A StatefulWidget combined with a Provider.value that wraps each route.
Example:
class Foo extends StatefulWidget {
#override
_FooState createState() => _FooState();
}
class _FooState extends State<Foo> {
int myState = 42;
#override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
'/': (_) => Provider.value(value: myState, child: Home()),
'/login': (_) => Provider.value(value: myState, child: Login()),
'/other': (_) => Other(),
},
);
}
}
A private placeholder type that wraps MaterialApp combined with ProxyProvider:
Example:
class _Scope<T> {
_Scope(this.value);
final T value;
}
// ...
Widget build(BuildContext context) {
Provider(
builder: (_) => _Scope(42),
child: MaterialApp(
routes: {
'/': (_) => ProxyProvider<_Scope<int>, int>(
builder: (_, scope, __) => scope.value, child: Home()),
'/login': (_) => ProxyProvider<_Scope<int>, int>(
builder: (_, scope, __) => scope.value, child: Login()),
'/other': (_) => Other(),
},
),
);
}
Related
I using BLoC. How to create it correctly, what would not arise due to the lack of widgets down the widget tree. Now I usually like this:
Widget build(BuildContext context) {
return MaterialApp(
// debugShowCheckedModeBanner: false,
theme: Styles.appTheme,
home: BlocProvider<TokenBloc>(
create: (context) => di.sl<TokenBloc>(),
child: _childTokenBloc,
),
);
}

Widget get _childTokenBloc {
return BlocBuilder<TokenBloc, TokenState>(builder: (context, state) {
if (state is TokenInitialState) {
context.read<TokenBloc>().add(TokenCheckEvent());
return const LogoImage();
}
if (state is TokenCheckState) {
return const LogoImage();
}
if (state is TokenOkState) {
return MainPageWidget();
}
if (state is TokenNoAuthorizationState) {
return const AuthorizationPageWidget();
}
return const LogoImage();
}
);
}
In AuthorizationPageWidget I do:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ConfirmAuthorizationPage()),
);
And from ConfirmAuthorizationPage I try to turn to TokenBloc:
context.read<TokenBloc>().add(TokenAddEvent());
but I get Error: Could not find the correct Provider above this App Widget
I thought that TokenBloc would be found in the widget tree, but is it not? And how to fix this problem? Need to use MultiBlocProvider in the build method of the ConfirmAuthorizationPage widget? It will be re-initialized, and the previous one will not be used.
Update 1:
Code AuthorizationPageWidget:
class AuthorizationPageWidget extends StatefulWidget {
const AuthorizationPageWidget({Key? key}) : super(key: key);
#override
_AuthorizationPageWidgetState createState() =>
_AuthorizationPageWidgetState();
}
class _AuthorizationPageWidgetState extends State<AuthorizationPageWidget> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider<AuthorizationBloc>(
create: (context) => sl<AuthorizationBloc>(),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_title,
_description,
Expanded(child: Align(alignment: FractionalOffset.bottomCenter, child: _bottomButton))
],
),
),
),
);
}
//......
void pushConfirmPage(String number) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ConfirmAuthorizationPage(number: number,)),
);
}
}
If you want to provide your Bloc in all your application, you have to write it in your MaterialApp like this, not in the body ;
return
BlocProvider<TokenBloc>( // like this
create: (context) => TokenBloc(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: _TokenHome(),
),
),
);
class _TokenHome extends StatelessWidget { // use a class instead of function
const _TokenHome({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocBuilder<TokenBloc, TokenState>(
builder: (context, state) {
if (state is TokenInitialState) {
context.read<TokenBloc>().add(TokenCheckEvent());
return const LogoImage();
}
if (state is TokenCheckState) {
return const LogoImage();
}
if (state is TokenOkState) {
return MainPageWidget();
}
if (state is TokenNoAuthorizationState) {
return const AuthorizationPageWidget();
}
return Container(
width: 50,
height: 50,
color: Colors.red,
); // use this if there is not a state
}
);
}
}
If for some reason it doesn't show anything anymore, then it's because some of your classes like AuthorizationPageWidget or LogoImage are wrong, check that.
-------- EDIT
Using BlocProvider on each page can be useful, but keep in mind that for example AuthorizationBloc will only work for its children, if you call it on another side of the screen it will not work, so it is highly recommended to use a MultiBlocProvider in MaterialApp to avoid future problems;
return MultiBlocProvider( // like this
providers: [
BlocProvider<TokenBloc>(
create: (context) => TokenBloc(),
),
BlocProvider<AuthorizationBloc>(
create: (context) => AuthorizationBloc(),
),
],
child: BlocBuilder<LanguageCubit, Locale?>(
builder: (context, lang) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
);
},
),
);
So all the other BlocProvider that you use to create, delete them, you do not need them, now if you use a BlocBuilder, BlocListeners of any Bloc, you would not have any inconvenience.
I've got an app having file structure like this: main -> auth -> home -> secret. Key codes are as below:
For main.dart:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<User>.value(value: AuthService().user),
ChangeNotifierProvider(create: (context) => SecretProvider()),
],
child: MaterialApp(
title: 'My Secrets',
home: AuthScreen(),
),
);
}
}
For home.dart:
class HomeScreen extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
var secretProvider = Provider.of<SecretProvider>(context);
return ChangeNotifierProvider(
create: (context) => SecretProvider(),
child: Scaffold(
appBar: AppBar(
// some codes...
),
body: StreamBuilder<List<Secret>>(
stream: secretProvider.secrets,
builder: (context, snapshot) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 15.0),
child: ListView.separated(
// return 0 if snapshot.data is null
itemCount: snapshot.data?.length ?? 0,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.web),
title: Text(snapshot.data[index].title),
trailing: Icon(Icons.edit),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecretScreen(
secret: snapshot.data[index],
),
),
);
},
);
},
separatorBuilder: (context, index) {
return Divider();
},
),
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecretScreen()),
);
},
),
),
);
}
}
For secret.dart:
class SecretScreen extends StatefulWidget {
final Secret secret;
SecretScreen({this.secret});
#override
_SecretScreenState createState() => _SecretScreenState();
}
class _SecretScreenState extends State<SecretScreen> {
// some codes...
#override
void initState() {
final secretProvider = Provider.of<SecretProvider>(context, listen: false);
// some codes...
super.initState();
}
#override
void dispose() {
// some codes...
super.dispose();
}
#override
Widget build(BuildContext context) {
final secretProvider = Provider.of<SecretProvider>(context);
return Scaffold(
// some codes...
);
}
}
These codes worked just fine, but later on I decided to move the ChangeNotifierProvider from main.dart to home.dart due to some class instance life cycle issue. The new code is like below:
For main.dart:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<User>.value(value: AuthService().user),
],
child: MaterialApp(
title: 'My Secrets',
home: AuthScreen(),
),
);
}
}
For home.dart:
class HomeScreen extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
// var secretProvider = Provider.of<SecretProvider>(context);
return ChangeNotifierProvider(
create: (context) => SecretProvider(),
child: Consumer<SecretProvider>(
builder: (context, secretProvider, child) {
return Scaffold(
appBar: AppBar(
// some codes...
),
body: StreamBuilder<List<Secret>>(
stream: secretProvider.secrets,
// stream: SecretProvider().secrets,
builder: (context, snapshot) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 15.0),
child: ListView.separated(
// return 0 if snapshot.data is null
itemCount: snapshot.data?.length ?? 0,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.web),
title: Text(snapshot.data[index].title),
trailing: Icon(Icons.edit),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecretScreen(
secret: snapshot.data[index],
),
),
);
},
);
},
separatorBuilder: (context, index) {
return Divider();
},
),
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecretScreen()),
);
},
),
);
},
),
);
}
}
Basically, I just moved the ChangeNotifierProvider to home.dart and used a Consumer to pass the context, but this time, whenever I navigate to secret screen, it prompts me error like below:
Could not find the correct Provider<SecretProvider> above this SecretScreen Widget
This likely happens because you used a `BuildContext` that does not include the provider
of your choice.
This BuildContext is really bugging me. Even if I'm having ChangeNotifierProvider one level lower than before, the SecretScreen widget should still be aware of the SecretProvider that passed on from HomeScreen because it's still the child of HomeScreen and according to my knowledge, the context should contain the SecretProvider.
You get this error because your SecretProvider instance is part of HomeScreen which is not a parent of SecretScreen.
In order, when you push a new page, this new page is not a descendent of the previous one so you can't access to inherited object with the .of(context) method.
Here the a schema representing the widget tree to explain the situation :
With a Provider on top of MaterialApp (the navigator) :
Provider
MaterialApp
HomeScreen -> push SecretScreen
SecretScreen -> Here we can acces the Provider by calling Provider.of(context) because the context can access to its ancestors
With a Provider created in HomeScreen :
MaterialApp
HomeScreen -> push SecretScreen
Provider -> The provider is part of HomeScreen
SecretScreen -> The context can't access to the Provider because it's not part of its ancestors
I hope my answer is pretty clear and will help you to understand what happens ;)
https://pub.dev/packages/provider
Can I use Provider to provide blocs globally to all widgets down the tree without MaterialApp? I tried to provide BLoC to a page, but when I'm navigating to the next page, BloC isn't found. So should I provide it whenever I'm navigating to a new page or is there a solution to provide it globally without MaterialApp?
Currently I'm doing it this way
Provider
|_MaterialApp
|_MyPage1 (from which you can navigate to MyPage2...3)
This approach works, and all pages can access provided BLoC.
But if use this approach
Provider
|_MyPage1 (from which you can navigate to MyPage2...3)
MyPage2, MyPage3 can't find provided BLoC. BLoC only can be found on MyPage1
You can achieve this by using the builder property of a MaterialApp.
lib/main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class SomeBloc {
final String someValue;
SomeBloc(this.someValue);
void dispose() {}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
SomeBloc _someBloc = SomeBloc("someValue");
#override
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, widget) => Provider<SomeBloc>(
create: (_) => _someBloc,
dispose: (_, bloc) => bloc.dispose(),
child: widget,
),
initialRoute: '/first-page',
routes: <String, WidgetBuilder>{
'/first-page': (context) => FirstPage(),
'/second-page': (context) => SecondPage(),
},
);
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
SomeBloc _someBloc = Provider.of<SomeBloc>(context);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(_someBloc.someValue),
RaisedButton(
child: Text("Open second page"),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => SecondPage(),
),
),
)
],
),
),
);
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
SomeBloc _someBloc = Provider.of<SomeBloc>(context);
return Scaffold(
body: Center(
child: Text(_someBloc.someValue),
),
);
}
}
Per the documentation,
home
The difference between using home and using builder is that the home subtree is inserted into the application below a Navigator.
builder
... the widget returned from builder is inserted above the app's Navigator (if any).
If you want your "blocs" to be provided on all of your routes, you have to provide those above the Navigator widget.
That's why this simply works:
return Provider(
create: (_) => _someBloc,
child: MaterialApp(
home: FirstPage(),
),
);
In this setup above, Provider is on top of the Navigator widget.
And this doesn't:
return MaterialApp(
home: Provider(
create: (_) => _someBloc,
child: FirstPage(),
),
);
_someBloc will only be accessible to the FirstPage widget.
Hope this helps.
I have a problem with Flutter Provider pattern. After user is redirected to a new screen, the provider could not be found.
Following my previous question (Could not find the correct provider above this widget)
I wrote this code:
class NewRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
final title = 'Tap to select';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: NewRouteBody()
));
}
}
class NewRouteBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
var user = Provider.of<UserRepository>(context);
return ListView(...)
I did same thing but I get again the error which says that it could not find the correct provider above this widget (NewRouteBody).
Tried to fix it somehow, Googled the answer for a few hours but without success...
Any help is appreciated.
EDIT
This is UserRepository which contains pattern:
class UserRepository with ChangeNotifier {
User user;
Status _status = Status.Uninitialized;
Status get status => _status;
User get getUser => user;
...}
EDIT 2:
Code snippet with ChangeNotifier:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.red,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<UserRepository>(
builder: (context) => UserRepository.instance(),
child: Consumer<UserRepository>(
builder: (context, UserRepository userRepository, _) {
switch (userRepository.status) {
case Status.Uninitialized:
return Login();
case Status.Unauthenticated:
return Login();
case Status.Authenticating:
case Status.Authenticated:
if(userRepository.getUser.isPrefSet == 0){
return Selection();
}
return Dashboard();
}
},
),
);
}
}
The issue is:
Your ChangeNotifierProvider is located inside Home, but you are trying to access it outside Home.
Providers are scoped. Which means that if it's located inside a widget tree, only its descendants can access it. As such, in your code, only Home can read from the provider.
To fix that, move the provider above MaterialApp:
ChangeNotifierProvider<UserRepository> (
builder: (context) => UserRepository(),
child: MaterialApp(
home: Home(),
),
)
You first need to create the Provider and place in the tree above the usage.
for example, in your case:
Widget build(BuildContext context) {
final title = 'Tap to select';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Provider<UserRepository> (
builder: (context) => UserRepository(),
dispose: (context, val) => val.dispose(),
child: NewRouteBody())
));
}
When the application reports such an error, it can be from many reasons. In my case, I was trying to read data from a context that was not wrapped by the BlocProvider from its ancestor.
// In my Child Widget
Navigator.push(context, MaterialPageRoute(
builder: (_) => MultiBlocProvider(providers: [
BlocProvider.value(
value: SaveJobsCubit()),
BlocProvider.value(
value: context.read<OnlineCompaniesCubit>()),
BlocProvider.value(
value: context.read<ApplyJobsCubit>()),
],
child: AttractiveJobsScreen(),
)
// But in Parent Widget, I create MultiBlocProvider with case have access_token
AuthRepo.accessToken != null
? RepositoryProvider(
create: (context) => OnlineCompaniesRepo(),
child: MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => SaveJobsCubit(),
),
BlocProvider(
create: (context) => OnlineCompaniesCubit(context.read<OnlineCompaniesRepo>()),
),
BlocProvider(
lazy: false,
create: (context) => ApplyJobsCubit(),
),
],
child: current,
),
)
: RepositoryProvider(
create: (context) => OnlineCompaniesRepo(),
child: BlocProvider(
create: (context) => OnlineCompaniesCubit(context.read<OnlineCompaniesRepo>()),
child: current,
),
);
This causes an error in case there is no access_token, then the child screen will not have SaveJobsCubit and cause the above error.
Hope this helps someone.
I want to use a CupertinoPageRoute instead of the Navigator.pushNamed
with a routes array in MaterialApp.
Navigator.pushNamed(context, p01.routeName); works fine. But I want to accomplish two items.
I want the navigation to be Cupertino Style in Android. Right To left, instead of Bottom to Top.
Navigation will go very deep, and I want to include a return button... like this. Navigator.popUntil(context,
ModalRoute.withName('/')); where I can return to specific locations
in the navigation Stack.
HOW can I use routes, namedRoutes
and
CupertinoPageRoute(builder: (context) => p02.routeName);
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'p01.dart';
import 'p02.dart';
import 'p03.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
initialRoute: '/',
// routes: {
// '/p01' : (context) => p01(),
// '/p02' : (context) => p02(),
// '/p03' : (context) => p03(),
// },
//***** . this is what I am trying to use for routes.
routes: <String, WidgetBuilder>{
p01.routeName: (BuildContext context) => new p01(title: "p01"),
p02.routeName: (BuildContext context) => new p02(title: "p02"),
p03.routeName: (BuildContext context) => new p03(title: "p03"),
},
);
}
}
...
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: Text(" cup P01"),
onPressed: () {
print("p01 was pressed");
//Navigator.pushNamed(context, p01.routeName);
// CupertinoPageRoute(builder: (context) => AA02Disclaimer()),
//CupertinoPageRoute(builder: (context) => p02());
// CupertinoPageRoute( p02.routeName );
// p02.routeName: (BuildContext context) => new p02(title: "p02"),
//**** . this is the code I am trying to make work...
CupertinoPageRoute(builder: (context) => p02.routeName);
},
),
),
=======
This is code to return to the root.
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: Text("/"),
onPressed: () {
print("/ was pressed");
// Navigator.pushNamed(context, p03.routeName);
Navigator.popUntil(context, ModalRoute.withName('/'));
},
),
),
TL;DR: Use onGenerate of MaterialApp / CupertinoApp to use custom routes. For example CupertinoPageRoute. If you are already using the Cupertino-Style consider using CupertinoApp, which automatically uses the CupertinoPageRoute.
I've split this answer in two solutions, one with the default MaterialAppand one with the CupertinoApp(using Cupertino-Style):
Keeping your style (MaterialApp):
If you want to keep the MaterialApp as your root widget you'll have to replace the routes attribute of your MaterialApp with an onGenerate implementation:
Original:
routes: {
'/': (_) => HomePage(),
'deeper': (_) => DeeperPage(),
}
Changed with onGenerate:
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/':
return CupertinoPageRoute(
builder: (_) => HomePage(), settings: settings);
case 'deeper':
return CupertinoPageRoute(
builder: (_) => DeeperPage(), settings: settings);
}
}
Now onGenerate handles the routing manually and uses for each route an CupertinoPageRoute. This replaces the complete routes: {...} structure.
Quick standalone example:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/':
return CupertinoPageRoute(
builder: (_) => HomePage(), settings: settings);
case 'deeper':
return CupertinoPageRoute(
builder: (_) => DeeperPage(), settings: settings);
}
},
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Material!'),
),
body: Center(
child: RaisedButton(
child: Text('Take me deeper!'),
onPressed: () => Navigator.pushNamed(context, 'deeper'),
),
),
);
}
}
class DeeperPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Material!'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
RaisedButton(
child: Text('Home :)'),
onPressed: () =>
Navigator.popUntil(context, ModalRoute.withName('/')),
),
RaisedButton(
child: Text('Deeper!'),
onPressed: () => Navigator.pushNamed(context, 'deeper'),
),
],
),
);
}
}
Cupterino Style (CupertinoApp):
If you want to use the Cupertino-Style anyway, I would suggest to use the CupertinoApp widget instead of the MaterialApp widget (like already suggested in a comment by #anmol.majhail).
Then the default chosen navigation will always use the CupertinoPageRoute.
Quick standalone example:
import 'package:flutter/cupertino.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoApp(
routes: {
'/': (_) => HomePage(),
'deeper': (_) => DeeperPage(),
},
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: Center(
child: CupertinoButton(
child: Text('Take me deeper!'),
onPressed: () => Navigator.pushNamed(context, 'deeper'),
),
),
);
}
}
class DeeperPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
CupertinoButton(
child: Text('Home :)'),
onPressed: () =>
Navigator.popUntil(context, ModalRoute.withName('/')),
),
CupertinoButton(
child: Text('Deeper!'),
onPressed: () => Navigator.pushNamed(context, 'deeper'),
),
],
),
);
}
}