I want to pass MaterialPageRoute as a parameter into another page. Like if want to pass onPressed((){}) to other page we declared it as
FirstPage({
this.onPressed,
});
final GestureTapCallback onPressed;
How could I pass MaterialPageRoute(builder: (context) => SecondPage()) to other page as a parameter?
Here's one way to do that:
class MyApp extends StatelessWidget {
const MyApp({Key? key}): super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: FirstPage(
materialPageRoute: MaterialPageRoute(builder: (context) => const SecondPage()),
)
);
}
}
class FirstPage extends StatelessWidget {
const FirstPage({
Key? key,
required this.materialPageRoute,
}): super(key: key);
final MaterialPageRoute materialPageRoute;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextButton(
onPressed: () => Navigator.of(context).push(materialPageRoute),
child: const Text('Navigate to SecondPage'),
),
)
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({Key? key}): super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: const Center(
child: Text('Second Page'),
),
);
}
}
Related
Background
I have a Navigator widget on my InitialPage and I am pushing two routes ontop of it (NestedFirstRoute and NestedSecondRoute). When I press the physical back button on Android, Both the routes in Navigator are popped (which is expected).
Use case
So I would like to handle this case when the back button is pressed only the top route (NestedSecondRoute) must be popped.
Solution I tried
To deal with this issue I have wrapped the Navigator widget in WillPopScope to handle the back button press events and assigned keys to nested routes so as to use them when popping routes in the willPop scope.
I get an exception on this line
if (NestedFirstPage.firstPageKey.currentState!.canPop()) {
Exception has occurred.
_CastError (Null check operator used on a null value)
Heres the minimal and complete code sample
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
final _navigatorKey = GlobalKey<NavigatorState>();
#override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: (settings) {
switch (settings.name) {
case NestedFirstPage.route:
return MaterialPageRoute(
builder: (context) {
return WillPopScope(
onWillPop: () async {
if (NestedFirstPage.firstPageKey.currentState!.canPop()) {
NestedFirstPage.firstPageKey.currentState!.pop();
return false;
} else if (NestedSecondPage.secondPageKey.currentState!
.canPop()) {
NestedSecondPage.secondPageKey.currentState!.pop();
return false;
}
return true;
},
child: Navigator(
key: _navigatorKey,
onGenerateRoute: (settings) {
switch (settings.name) {
case Navigator.defaultRouteName:
return MaterialPageRoute(
builder: (context) => const NestedFirstPage(),
settings: settings,
);
case NestedSecondPage.route:
return MaterialPageRoute(
builder: (context) => const NestedSecondPage(),
settings: settings,
);
}
},
),
);
},
settings: settings,
);
}
},
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const InitialPage(title: 'Initial Page'),
);
}
}
class InitialPage extends StatelessWidget {
const InitialPage({Key? key, required this.title}) : super(key: key);
final String title;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
OutlinedButton(
onPressed: () {
Navigator.pushNamed(context, NestedFirstPage.route);
},
child: const Text('Move to Nested First Page'),
),
],
),
),
);
}
}
class NestedFirstPage extends StatelessWidget {
const NestedFirstPage({Key? key}) : super(key: key);
static final GlobalKey<NavigatorState> firstPageKey =
GlobalKey<NavigatorState>();
static const String route = '/nested/first';
#override
Widget build(BuildContext context) {
return Scaffold(
key: firstPageKey,
appBar: AppBar(title: const Text('Nested First Page')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('First page'),
OutlinedButton(
child: const Text('Move to Nested Second Page'),
onPressed: () {
Navigator.pushNamed(context, NestedSecondPage.route);
},
),
],
),
),
);
}
}
class NestedSecondPage extends StatelessWidget {
const NestedSecondPage({Key? key}) : super(key: key);
static final GlobalKey<NavigatorState> secondPageKey =
GlobalKey<NavigatorState>();
static const String route = '/nested/second';
#override
Widget build(BuildContext context) {
return Scaffold(
key: secondPageKey,
appBar: AppBar(title: const Text('Nested Second Page')),
body: const Center(
child: Text('Second Page'),
),
);
}
}
Here's a slightly modified version of the above code which will allow pushing nested routes and can be popped via android back button
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'/nested/first': (context) => const NestedFirstPage(),
'/nested/first/second': (context) => const NestedSecondPage()
},
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const RouteManager());
}
}
class InitialPage extends StatelessWidget {
const InitialPage({Key? key, required this.title}) : super(key: key);
final String title;
static const String route = '/';
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (navigatorKey.currentState != null &&
navigatorKey.currentState!.canPop()) {
navigatorKey.currentState!.pop();
return true;
}
return false;
},
child: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
OutlinedButton(
onPressed: () {
navigate(context, NestedFirstPage.route);
},
child: const Text('Move to Nested First Page'),
),
],
),
),
),
);
}
}
Future<void> navigate(BuildContext context, String route,
{bool isDialog = false, bool isRootNavigator = true}) =>
Navigator.of(context, rootNavigator: isRootNavigator).pushNamed(route);
final navigatorKey = GlobalKey<NavigatorState>();
class RouteManager extends StatelessWidget {
const RouteManager({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
switch (settings.name) {
case '/nested/first':
builder = (BuildContext _) => const NestedFirstPage();
break;
case '/nested/first/second':
builder = (BuildContext _) => const NestedSecondPage();
break;
default:
builder =
(BuildContext _) => const InitialPage(title: 'Initial Page');
}
return MaterialPageRoute(builder: builder, settings: settings);
});
}
}
class NestedFirstPage extends StatelessWidget {
static final GlobalKey<NavigatorState> firstPageKey =
GlobalKey<NavigatorState>();
static const String route = '/nested/first';
const NestedFirstPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
key: firstPageKey,
appBar: AppBar(title: const Text('Nested First Page')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('First page'),
OutlinedButton(
child: const Text('Move to Nested Second Page'),
onPressed: () {
navigate(context, NestedSecondPage.route);
},
),
],
),
),
);
}
}
class NestedSecondPage extends StatelessWidget {
const NestedSecondPage({Key? key}) : super(key: key);
static final GlobalKey<NavigatorState> secondPageKey =
GlobalKey<NavigatorState>();
static const String route = '/nested/first/second';
#override
Widget build(BuildContext context) {
return Scaffold(
key: secondPageKey,
appBar: AppBar(title: const Text('Nested Second Page')),
body: const Center(
child: Text('Second Page'),
),
);
}
}
Heres a real world example with a Nested Bottomavigationbar.
How can I make the HomeScreen load after the Spinkit . I was able to add the spinkit loaders on my app, but I am unable to add the navigation in it so that it can runs the home screen automatically,
Please help
This is are the codes I have used in the spinkit page:
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:road_sign/screen/home/home_screen.dart';
class LoadingPage extends StatelessWidget {
const LoadingPage({Key? key}) : super(key: key);
void main(List<String> args) {
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green[50],
body: Center(
child: SpinKitThreeBounce(
size: 90,
color: Colors.green,
),
),
);
}
}
And these are codes of main.dart
import 'package:road_sign/screen/home/home_screen.dart';
import 'package:road_sign/screen/loadingScreen/loadingPage.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(
debugShowCheckedModeBanner: false,
title: 'Road Sign',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: LoadingPage(),
);
}
}
You can use an async method and add a delay before navigation.
Please check the below sample :
class LoadingPage extends StatefulWidget {
const LoadingPage({Key? key}) : super(key: key);
#override
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<LoadingPage> {
#override
void initState() {
autoNavigation();
super.initState();
}
void autoNavigation() async {
// you can change delay here
await Future.delayed(Duration(seconds: 1));
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green[50],
body: Center(
child: SpinKitThreeBounce(
size: 90,
color: Colors.green,
),
),
);
}
}
It will work, But I suggest using a state management solution to split logic from UI.
how to add floating action button inside tab navigation button ?
like the example in the screenshot, I want to add such a button. I've tried adding the floating action button command but instead the button is entered in the profile tab.
Here is the example for your problem:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatelessWidget(),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Floating Action Button'),
),
body: const Center(child: Text('Press the button below!')),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
backgroundColor: Colors.green,
child: const Icon(Icons.navigation),
),
);
}
}
Don't use FloatingActionButton in the body tag
FloatingActionButton has the separate tag under scaffold like this
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
backgroundColor: Colors.red,
child: const Icon(Icons.add),
),
);
I need to pass a id parameter to a separate page while navigating from one page to another, I am currently using named routes to navigate but they are not letting me pass parameters.
You have to use the "final" variable in the second route class and pass the values during instantiation of that class' object.
The below navigation example was obtained from Flutter docs I just added the "passing data to a new page" process.
class FirstRoute extends StatelessWidget {
const FirstRoute({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("First Route"),
),
body: Center(
child: ElevatedButton(
child: const Text("Open route"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const SecondRoute(text: "This is the text")),
);
},
),
),
);
}
}
class SecondRoute extends StatelessWidget {
const SecondRoute({Key? key, required this.text}) : super(key: key);
final String text;
#override
Widget build(BuildContext context) {
print(text);
return Scaffold(
appBar: AppBar(
title: const Text("Second Route"),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("Go back!"),
),
),
);
}
}
I'm not able to navigate screen showing error 'Navigator operation requested with a context that does not include a Navigator, I have tried many solutions where navigator is used in Builder with stateless widgets but here navigation is done automatically after a few seconds in override method in intiSate. my aim is to navigate the screen after a few seconds.
class Splash extends StatelessWidget {
#override
Widget build(BuildContext context) {
return testWidget;
}
}
Widget testWidget = new MediaQuery(
data: new MediaQueryData(),
child: new MaterialApp( title: 'xxxxxxxxxxxxx',
home: SplashScreen(),
debugShowCheckedModeBanner: false,
routes: <String, WidgetBuilder>{
'/login': (BuildContext context) => new Login(),
},
)
);
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
Future initState () {
super.initState();
new Future.delayed(
const Duration(seconds: 2), () => Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => Login()),
));
}
#override
Widget build(BuildContext context) {
return(Scaffold(
body: Container(
height: double.infinity,
width: double.infinity,
child: Image.asset('assets/images/crop.jpg',fit:BoxFit.fill),
),
));
//build
}
}
Showing Error
Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
Code Corrected:
MaterialApp Should always be the Root Widget of all Widgets.
That Way Navigator is always Available.
void main() => runApp(Splash());
class Splash extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: testWidget,
debugShowCheckedModeBanner: false,
);
}
}
Widget testWidget =
new MediaQuery(data: new MediaQueryData(), child: new SplashScreen());
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
super.initState();
Future.delayed(
const Duration(seconds: 2),
() => Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => Login()),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Spalsh'),),
body: Container(
height: double.infinity,
width: double.infinity,
// child: Image.asset('assets/images/crop.jpg', fit: BoxFit.fill),
),
);
//build
}
}
class Login extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Login Page'),
),
body: Container(),
);
}
}