Navigate to a new screen in Flutter - dart

How do you navigate to a new screen in Flutter?
These questions are similar, but are asking more than I am.
Flutter - Navigate to a new screen, and clear all the previous screens
Flutter: How do I navigate to a new screen using DropDownMenuItems
Flutter: Move to a new screen without back
flutter navigation to new screen not working
I am adding an answer below.

Navigate to a new screen:
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewScreen()));
where context is the BuildContext of a widget and NewScreen is the name of the second widget layout.
Code
main.dart
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),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Screen')),
body: Center(
child: ElevatedButton(
child: const Text(
'Navigate to a new screen >>',
style: TextStyle(fontSize: 24.0),
),
onPressed: () {
_navigateToNextScreen(context);
},
),
),
);
}
void _navigateToNextScreen(BuildContext context) {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewScreen()));
}
}
class NewScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('New Screen')),
body: const Center(
child: Text(
'This is a new screen',
style: TextStyle(fontSize: 24.0),
),
),
);
}
}
See also
Documentation
Navigator and Routes and Transitions... Oh, My! - Simon Lightfoot | Flutter Europe

To load new screens with Flutter pre-canned animations, use their respective transition classes. For example:
Container Transformation
Basically we have the first widget or screen transform into the next screen. For this we need to use OpenContainer. The following code illustrates an item in a ListView transformed to its details page.
#override
Widget build(BuildContext context) {
return Card(
color: Colors.white,
elevation: 2.0,
child: OpenContainer(
transitionType: ContainerTransitionType.fadeThrough,
closedColor: Theme.of(context).cardColor,
closedElevation: 0.0,
openElevation: 4.0,
transitionDuration: Duration(milliseconds: 1500),
openBuilder: (BuildContext context, VoidCallback _) => THENEXTSCREEN(),
closedBuilder: (BuildContext _, VoidCallback openContainer) {
return ListTile(
leading: Icon(Icons.album),
title: Text("ITEM NAME"),
);
},
),
);
}
Shared Axis
This transition is similar to that in Tab or Stepper. We need SharedAxisTransition, PageTransitionSwitcher, along with a state to model transition between active and previous page. If we only switch between two pages we can use a simple boolean isFirstPage for it. Here's the snippet with Provider as state management:
#override
Widget build(BuildContext context) {
return Consumer<YourState>(
builder: (context, state, child) {
return PageTransitionSwitcher(
duration: const Duration(milliseconds: 1500),
reverse: !state.isFirstPage, // STATE
transitionBuilder: (
Widget child,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return SharedAxisTransition(
child: child,
animation: animation,
secondaryAnimation: secondaryAnimation,
transitionType: SharedAxisTransitionType.horizontal,
);
},
child: state.isFirstPage? FIRSTPAGE() : SECONDPAGE(), // STATE
);
},
);
}
Note that in all these scenarios we don't use Navigator and MaterialPageRoute. All these codes are derived from animations repo so you may want to check it out first.

Navigate to next screen with back using Navigator.push()
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),);
Navigate to next screen without back using Navigator.pushReplacement()
Navigator.pushReplacement(
context,MaterialPageRoute(builder: (context) => SecondRoute()),);

onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => NextScreenName()));
}

If you are familiar with web development this approach is similar to routing.
main.dart
void main() {
setupLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'/' : (BuildContext context)=>HomePage(),
'/register' : (BuildContext context)=>RegisterPage(),
},
);
}
}
You can add button onPressed event from the homepage.dart to navigate register.dart as follows.
onPressed: (){
Navigator.pushReplacementNamed(context, '/register');
},

Here is a full example of routes push / pop:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Routes',
routes: {
'/login': (BuildContext context) => Login(),
// add another route here
// '/register': (BuildContext context) => Register(),
},
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Routes'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
onPressed: () {
// This gives the back button:
Navigator.of(context).pushNamed('/login');
// This doesn't give the back button (it replaces)
//Navigator.pushReplacementNamed(context, '/login');
},
child: Text('Login'),
),
],
),
),
);
}
}
class Login extends StatefulWidget {
#override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Login Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
// This will only work for pushNamed
Navigator.of(context).pop();
},
child: Text('Go back'),
),
));
}
}

you can use that way in your build widget
onTap: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => NewScreen()));},

In formal method :
Navigator.push(context, MaterialPageRoute(builder: (context)=>Second()));
In GetX method :
Get.to(Second());
If we can navigate screen into another page and delete current page from stack then we can use method which is define below :
Get.off(Third());
If we can navigate screen into another page and delete all route or page from stack then we can use the method which is define below :
Get.offAll(Third());
If we want to use Navigator.pop() then GetX give a Method which is define below :
Get.back();

You can try with the following code
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => YourNextScreen())),

I found a good tutorial that I have followed along, it is very comprehensive with screenshots and step by step, you can also download the code and just run it. Very helpful for me learning Flutter especially I am totally a begineer.
https://medium.com/#misterflutter/lesson-5-creating-new-screens-f740994190c7
https://medium.com/#misterflutter/lesson-6-creating-new-screens-part-2-4997085a43af?sk=d2a0fb723af42b78800f7cf19b312b62

With the Get plugin, you can navigate to a new page by simply calling
Get.to(Page());

This way you can present the next screen
Navigator.of(context).push(
MaterialPageRoute(fullscreenDialog: true,
builder: (context) => const NewScreen(),
),
);

FloatingActionButton(
onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context) => const AddUser()));
},
child: const Icon(Icons.add),
),

Related

Flutter: Offstage with Navigator inside not getting focus

In my App I have a bottom bar that is always visible. I found in this site that a good way to keep tabs in memory while also having multiple navigators is by using Offscreen. However, when I put a Navigator inside Offscreen none of its contents can receive focus. I made a very simple example that reproduces what I'm saying:
void main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomeScreen(),
);
}
}
class MyHomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
body: Stack(
children: [
Offstage(
offstage:false,
child: Navigator(
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute(
builder: (BuildContext context) {
return Center(child: TextField());
},
);
},
),
),
Offstage(
offstage:true,
child: Navigator(
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute(
builder: (BuildContext context) {
return Center(child: TextField());
},
);
},
),
),
],
),
),
);
}
}
If you click on the TextField, it will not receive focus, so the user cannot type anything.
Is there any way to direct focus to the active (visible) offscreen ?
Any other suggestion for this problem?
Thanks
That is a current issue in Github. To solve it you need to put a FocusScope widget on top of each Navigator.
This comment in the GH thread has an example:
https://github.com/flutter/flutter/issues/17098#issuecomment-414610135

StatefulWidget:Navigator operation requested with a context that does not include a Navigator [duplicate]

I'm trying to start a new screen within an onTap but I get the following error:
Navigator operation requested with a context that does not include a
Navigator.
The code I am using to navigate is:
onTap: () { Navigator.of(context).pushNamed('/settings'); },
I have set up a route in my app as follows:
routes: <String, WidgetBuilder>{
'/settings': (BuildContext context) => new SettingsPage(),
},
I've tried to copy the code using the stocks sample application. I've looked at the Navigator and Route documentation and can't figure out how the context can be made to include a Navigator. The context being used in the onTap is referenced from the parameter passed into the build method:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
SettingsPage is a class as follows:
class SettingsPage extends Navigator {
Widget buildAppBar(BuildContext context) {
return new AppBar(
title: const Text('Settings')
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: buildAppBar(context),
);
}
}
TLDR: Wrap the widget which needs to access to Navigator into a Builder or extract that sub-tree into a class. And use the new BuildContext to access Navigator.
This error is unrelated to the destination. It happens because you used a context that doesn't contain a Navigator instance as parent.
How do I create a Navigator instance then ?
This is usually done by inserting in your widget tree a MaterialApp or WidgetsApp. Although you can do it manually by using Navigator directly but less recommended. Then, all children of such widget can access NavigatorState using Navigator.of(context).
Wait, I already have a MaterialApp/WidgetsApp !
That's most likely the case. But this error can still happens when you use a context that is a parent of MaterialApp/WidgetsApp.
This happens because when you do Navigator.of(context), it will start from the widget associated to the context used. And then go upward in the widget tree until it either find a Navigator or there's no more widget.
In the first case, everything is fine. In the second, it throws a
Navigator operation requested with a context that does not include a Navigator.
So, how do I fix it ?
First, let's reproduce this error :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
),
);
}
}
This example creates a button that attempts to go to '/' on click but will instead throw an exception.
Notice here that in the
onPressed: () => Navigator.pushNamed(context, "/"),
we used context passed by to build of MyApp.
The problem is, MyApp is actually a parent of MaterialApp. As it's the widget who instantiate MaterialApp! Therefore MyApp's BuildContext doesn't have a MaterialApp as parent!
To solve this problem, we need to use a different context.
In this situation, the easiest solution is to introduce a new widget as child of MaterialApp. And then use that widget's context to do the Navigator call.
There are a few ways to achieve this. You can extract home into a custom class :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHome()
);
}
}
class MyHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
);
}
}
Or you can use Builder :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
),
),
);
}
}
Hy guys, i have the same problem. This is occur for me. The solution what i found is very simple. Only what i did is in a simple code:
void main() {
runApp(MaterialApp(
home: YOURAPP() ,
),
);
}
I hope was useful.
Make sure your current parent widget not with same level with MaterialApp
Wrong Way
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Title'),
),
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: RaisedButton(
onPressed: () {
//wrong way: use context in same level tree with MaterialApp
Navigator.push(context,
MaterialPageRoute(builder: (context) => ScanScreen()));
},
child: const Text('SCAN')),
)),
),
);
}
}
Right way
void main() => runApp(MaterialApp(
title: "App",
home: HomeScreen(),
));
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Title'),
),
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: RaisedButton(
onPressed: () {
//right way: use context in below level tree with MaterialApp
Navigator.push(context,
MaterialPageRoute(builder: (context) => ScanScreen()));
},
child: const Text('SCAN')),
)),
);
}
}
Just like with a Scaffold you can use a GlobalKey. It doesn't need context.
final _navKey = GlobalKey<NavigatorState>();
void _navigateToLogin() {
_navKey.currentState.popUntil((r) => r.isFirst);
_navKey.currentState.pushReplacementNamed(LoginRoute.name);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: _navKey,
...
);
}
I set up this simple example for routing in a flutter app:
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(),
routes: <String, WidgetBuilder>{
'/settings': (BuildContext context) => new SettingsPage(),
},
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('TestProject'),
),
body: new Center(
child: new FlatButton(
child: const Text('Go to Settings'),
onPressed: () => Navigator.of(context).pushNamed('/settings')
)
)
);
}
}
class SettingsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('SettingsPage'),
),
body: new Center(
child: new Text('Settings')
)
);
}
}
Note, that the SettingsPage extends StatelessWidget and not Navigator. I'm not able to reproduce your error.
Does this example help you in building your app? Let me know if I can help you with anything else.
You should rewrite your code in main.dart
FROM:
void main() => runApp(MyApp());
TO
void main() {
runApp(MaterialApp(
title: 'Your title',
home: MyApp(),));}
The point is to have the home property to be your first page
this worked for me, I hope it will help someone in the future
A complete and tested solution:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:my-app/view/main-view.dart';
class SplashView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: Builder(
builder: (context) => new _SplashContent(),
),
routes: <String, WidgetBuilder>{
'/main': (BuildContext context) => new MainView()}
);
}
}
class _SplashContent extends StatefulWidget{
#override
_SplashContentState createState() => new _SplashContentState();
}
class _SplashContentState extends State<_SplashContent>
with SingleTickerProviderStateMixin {
var _iconAnimationController;
var _iconAnimation;
startTimeout() async {
var duration = const Duration(seconds: 3);
return new Timer(duration, handleTimeout);
}
void handleTimeout() {
Navigator.pushReplacementNamed(context, "/main");
}
#override
void initState() {
super.initState();
_iconAnimationController = new AnimationController(
vsync: this, duration: new Duration(milliseconds: 2000));
_iconAnimation = new CurvedAnimation(
parent: _iconAnimationController, curve: Curves.easeIn);
_iconAnimation.addListener(() => this.setState(() {}));
_iconAnimationController.forward();
startTimeout();
}
#override
Widget build(BuildContext context) {
return new Center(
child: new Image(
image: new AssetImage("images/logo.png"),
width: _iconAnimation.value * 100,
height: _iconAnimation.value * 100,
)
);
}
}
As per this comment If your navigator is inside Material context navigator push will give this error. if you create a new widget and assign it to the material app home navigator will work.
This won't work
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text("Title"),
),
body: new Center(child: new Text("Click Me")),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
backgroundColor: Colors.orange,
onPressed: () {
print("Clicked");
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new AddTaskScreen()),
);
},
),
),
);
}
}
This will work
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new HomeScreen());
}
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Title"),
),
body: new Center(child: new Text("Click Me")),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
backgroundColor: Colors.orange,
onPressed: () {
print("Clicked");
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new AddTaskScreen()),
);
},
),
);
}
}
I was facing the same problem and solved by removing home from MaterialApp and use initialRoute instead.
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
'/': (context) => MyApp(),
'/settings': (context) => SettingsPage(),
},
);
And
onTap: () => {
Navigator.pushNamed(context, "/settings")
},
It is Simple
instead using this normal code
`runApp(BasicBankingSystem());`
wrap it with MaterialApp
runApp(MaterialApp(home: BasicBankingSystem()));
It happens because the context on the widget that tries to navigate is still using the material widget.
The short answer for the solution is to :
extract your widget
that has navigation to new class so it has a different context when calling the navigation
When your screen is not navigated from other screen,you don't initially have access to the navigator,Because it is not instantiated yet.So in that case wrap your widget with builder and extract context from there.This worked for me.
builder: (context) => Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
You ca use this plugin
https://pub.dev/packages/get/versions/2.0.2
in The MaterialApp assign property navigatorKey: Get.key,
MaterialApp(
navigatorKey: Get.key,
initialRoute: "/",
);
you can access Get.toNamed("Your route name");
Change your main function example:
void main() {
runApp(
MaterialApp(
title: 'Your title',
home: MyApp(),
)
);
}
use this
void main() {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}
instead of this
void main() {runApp(MyApp());}
Wrap with materialapp
reproduce code
import 'dart:convert';
import 'package:flutter/material.dart';
void main() {
// reproduce code
runApp(MyApp());
// working switch //
// runApp(
//
// MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body:
Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 100,
width: 100,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => IntroPage(Isscar4: true)),
);
},
child: RichText(
text: TextSpan(
text: 'CAR',
style: TextStyle(
letterSpacing: 3,
color: Colors.white,
fontWeight: FontWeight.w400),
children: [
TextSpan(
text: '4',
style: TextStyle(
fontSize: 25,
color: Colors.red,
fontWeight: FontWeight.bold))
],
)),
),
),
],
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 100,
width: 100,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => IntroPage(Isscar4: false)),
);
},
child: RichText(
text: TextSpan(
text: 'BIKE',
style: TextStyle(
letterSpacing: 3,
color: Colors.white,
fontWeight: FontWeight.w400),
children: [
TextSpan(
text: '2',
style: TextStyle(
fontSize: 25,
color: Colors.red,
fontWeight: FontWeight.bold))
],
)),
),
),
],
)
])));
}
MaterialApp Swithwidget(istrue) {
return MaterialApp(
home: Scaffold(
body: IntroPage(
Isscar4: istrue,
),
),
);
}
}
class Hi extends StatelessWidget {
const Hi({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Text("df"),
);
}
}
class IntroPage extends StatelessWidget {
final Isscar4;
IntroPage({
Key? key,
required this.Isscar4,
}) : super(key: key);
List<Widget> listPagesViewModel = [];
List<IntroModel> models = [];
#override
Widget build(BuildContext context) {
List<dynamic> intro = fetchIntroApi(Isscar4);
intro.forEach((element) {
var element2 = element as Map<String, dynamic>;
var cd = IntroModel.fromJson(element2);
models.add(cd);
});
models.forEach((element) {
listPagesViewModel.add(Text(""));
});
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container(),
));
}
List fetchIntroApi(bool bool) {
var four = bool;
if (four) {
var data =
'[ {"name_Title": "title name1","description": "description1"}, {"name_Title": "title name2","description": "description2"}, {"name_Title": "title name3","description": "description3"}, {"name_Title": "title name4","description": "description4"} ]';
return json.decode(data);
} else {
var data =
'[ {"name_Title": "title name","description": "description1"}, {"name_Title": "title name2","description": "description2"}, {"name_Title": "title name3","description": "description3"} ]';
return json.decode(data);
}
}
}
class IntroModel {
String? nameTitle;
String? description;
IntroModel({this.nameTitle, this.description});
IntroModel.fromJson(Map<String, dynamic> json) {
nameTitle = json['name_Title'];
description = json['description'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name_Title'] = this.nameTitle;
data['description'] = this.description;
return data;
}
}
class Splash extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Splash Screen',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: MyState(),
debugShowCheckedModeBanner: false,
);
}
void main() {
runApp(Splash());
}
class MyState extends StatefulWidget{
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyState> {
#override
void initState() {
super.initState();
Timer(Duration(seconds: 3),
()=>Navigator.pushReplacement(context,
MaterialPageRoute(builder:
(context) =>
Login()
)
)
);
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center ,
children: [
Container(
child:
Image.asset("assets/images/herosplash.png"),
),
],
),
);
}
}
Builder(
builder: (context) {
return TextButton(
child: const Text('Bearbeiten'),
onPressed:(){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const gotothesiteyouwant()),
);
});
}
),
Here, all you need is to make MaterialApp the parent of your Build. This is because the context that you've used to navigate to a different screen is finding a MaterialApp or a WidgetApp as a parent of the build.
And Since in your case, the situation is the opposite, therefore you need to modify it by either calling a new Stateless widget the parent of is the MaterialApp or by simply using a Builder as home: Builder in MaterialApp.
Hope this would help!

Flutter: How to display a snackbar from an appbar action

I'm trying to display a SnackBar after performing an action from the AppBar.
The AppBar cannot be built from a builder so it can't access is Scaffold ancestor.
I know we can use a GlobalKey object to access the context whenever we want, but I would like to know if there is a solution without using the GlobalKey.
I found some github issues and pull-request, but I can't find a solution from them
=> https://github.com/flutter/flutter/issues/4581 and https://github.com/flutter/flutter/pull/9380
Some more context:
I have an Appbar with a PopupMenuButton, which have one item. When the user click on this item I display a dialog which the showDialog method and if the user clicks on "ok" I want to display a SnackBar
You can use the Builder widget
Example:
Scaffold(
appBar: AppBar(
actions: <Widget>[
Builder(
builder: (BuildContext context) {
return IconButton(
icon: const Icon(Icons.message),
onPressed: () {
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
Scaffold.of(context).showSnackBar(snackBar);
},
);
},
),
],
)
);
The Scaffold.appBar parameter requires a PreferredSizeWidget, so you can have a Builder there like this:
appBar: PreferredSize(
preferredSize: Size.fromHeight(56),
child: Builder(
builder: (context) => AppBar(...),
),
),
An option is to use two contexts in the dialog and use the context passed to the dialog to search for the Scaffold.
When you show a dialog, you are displaying a completely different page/route which is outside the scope of the calling page. So no scaffold is available.
Below you have a working example where you use the scope of the first page.
The problem, though, is that the SnackBar is not removed.
If instead you use a GlobalKey to get the Scaffold the problem is the same.
I would consider not using a Snackbar in this case, because it is associated to the page below. It is even greyed out by the dialog shadow.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
_showDialog(BuildContext context1) {
return showDialog(
context: context1,
builder: (BuildContext context) {
return AlertDialog(
content: Text("Dialog"),
actions: <Widget>[
new FlatButton(
child: new Text("OK"),
onPressed: () => Scaffold.of(context1).showSnackBar(SnackBar(
content: Text("Pressed"),
)),
),
],
);
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Test"),
actions: <Widget>[
PopupMenuButton(
itemBuilder: (BuildContext context) {
return <PopupMenuEntry>[
PopupMenuItem(
child: ListTile(
title: Text('Show dialog'),
onTap: () => _showDialog(context),
),
),
];
},
)
],
),
);
}
}

Flutter Snackbar dismiss listener

I was looking for a way to check if the Snackbar has been dismissed, either by the user or by the timeout stuff. I could't really get any listener of doing it.
This is what I got so far,
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text("Title")))
.closed
.then((reason) {
// snackbar is now closed
});
This is the one way around, I was looking for exact listener. I don't want any work around, like setting duration of Snackbar and then listening to it after the duration has passed.
see full example below
I just wrapped SnackBar content with WillPopoScope and if the user pressed back button it will remove snackbar.
By default it will specify SnackBarClosedReason.remove reason
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: FirstPage(),
),
);
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: Text('go to test page'),
onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => Test())),
),
);
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
child: Text('show snack'),
onPressed: () => _showSnack(context),
),
),
);
}
void _showSnack(BuildContext context) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: WillPopScope(
onWillPop: () async {
ScaffoldMessenger.of(context).removeCurrentSnackBar();
return true;
},
child: Text("Title"),
),
),
)
.closed
.then((reason) {
print('------------ $reason');
});
}
}

Flutter - SimpleDialog in FloatingActionButton

I'm trying to create a SimpleDialog after a tap on the FloatingActionButton, however when pressing that button nothing happens.
What was I doing wrong?
import "package:flutter/material.dart";
void main() {
runApp(new ControlleApp());
}
class ControlleApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) => new Scaffold(
appBar: new AppBar(
backgroundColor: new Color(0xFF26C6DA),
),
floatingActionButton: new FloatingActionButton(
tooltip: 'Add',
child: new Icon(Icons.add),
backgroundColor: new Color(0xFFF44336),
onPressed: (){
new SimpleDialog(
title: new Text('Test'),
children: <Widget>[
new RadioListTile(
title: new Text('Testing'), value: null, groupValue: null, onChanged: (value) {},
)
],
);
}
),
);
}
I noticed the accepted answer is using child for showDialog which is actually deprecated, so I would recommend avoiding it. You should be using builder instead, I've provided an example:
onPressed: () {
showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text('Dialog Title'),
content: Text('This is my content'),
)
);
}
You need to wrap this on a show action dialog.
showDialog(context: context, builder: (BuildContext context) {
return new AlertDialog(
title: new Text("My Super title"),
content: new Text("Hello World"),
);
}
There is a specific scenario which should be taken care while showing the dialog from floatingActionButton
if you write your code like this
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (ctxt) => new AlertDialog(
title: Text("Text Dialog"),
)
);
}),
)
);
}
}
It will not show Alert Dialog but throws an exception "No MaterialLocalizations found."
This happens when the MaterialApp is not the root where the dialog is called. In this case the root widget is the Application. However, if we change the code as
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyAppImpl()
);
}
}
class MyAppImpl extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (ctxt) => new AlertDialog(
title: Text("Text Dialog"),
)
);
}),
);
}
}
The MaterialApp becomes the root and everything works fine. In this case flutter automatically creates Material Localiation which otherwise needs to be manually created.
I didn't find any documentation for the same in the official doc.
Hope it helps

Resources