I am trying to get data back from the second screen to the first one:
...
onPressed: () {
sendDataBack(context);
},
...
void sendDataBack(BuildContext context) {
int minSendBack = int.parse(minValueController.text);
int maxSendBack = int.parse(maxValueController.text);
Navigator.pop(context,...);
}
When I use Navigator.pop(context, MaterialPageRout(builder: (context) => main(...)))
I get the error the return type 'void' isn't a 'Widget'. How do I pass two variables back?
Take a look at the following example:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Returning Data',
home: HomeScreen(),
));
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Returning Data Demo'),
),
body: Center(child: SelectionButton()),
);
}
}
class SelectionButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: Text('Pick an option, any option!'),
);
}
// A method that launches the SelectionScreen and awaits the result from
// Navigator.pop.
_navigateAndDisplaySelection(BuildContext context) async {
// Navigator.push returns a Future that completes after calling
// Navigator.pop on the Selection Screen.
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("$result")));
}
}
class SelectionScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pick an option'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Yep!" as the result.
Navigator.pop(context, 'Yep!');
},
child: Text('Yep!'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Nope!" as the result.
Navigator.pop(context, 'Nope.');
},
child: Text('Nope.'),
),
)
],
),
),
);
}
}
And read flutter docs carefully.
It's taken from Flutter.dev
you can try this:
in secondScreen Class:
...
onPeressed () {
Navigator.pop(context, returnedData);
}
...
in firstScreen Class:
...
onPeressed () {
result = await Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new secondScreen();
}
...
Related
I am trying to use solution from here
How make button which open random page in Flutter?
but instead of RaisedButton, do it with my Listview buttons.
Here's what I have so far after I added the RandomRouteGenerator from the other StackOverflow:
ListView(
children: const <Widget>[
Card(
child: ListTile(
leading: Text('🐔'),
title: Text('Chicken'),
onTap: () {
Navigator.of(context).pushNamed(
RouteGenerator.getRandomNameOfRoute());
},
),
),
//... more Cards that would become other listview items
Here's the errors:
Compiler message:
lib/main.dart:163:28: Error: Not a constant expression.
Navigator.of(context).pushNamed(
^^^^^^^
lib/main.dart:163:25: Error: Method invocation is not a constant expression.
Navigator.of(context).pushNamed(
^^
lib/main.dart:164:32: Error: Method invocation is not a constant expression.
RouteGenerator.getRandomNameOfRoute());
^^^^^^^^^^^^^^^^^^^^
lib/main.dart:163:37: Error: Method invocation is not a constant expression.
Navigator.of(context).pushNamed(
^^^^^^^^^
lib/main.dart:162:20: Error: Not a constant expression.
onTap: () {
^^
Thanks
You can copy paste run full code below
You can remove keyword const of children: const <Widget>[
code snippet
child: ListView(children: <Widget>[
Card(
working demo
full code
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Random pages',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: 'start_page',
onGenerateRoute: RouteGenerator.generateRoute,
);
}
}
class RouteGenerator {
static List<String> myRandomPages = ['first_page', 'second_page'];
static String getRandomNameOfRoute() {
return myRandomPages[Random().nextInt(myRandomPages.length)];
}
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case 'start_page':
return MaterialPageRoute(builder: (_) => StartPage());
case 'first_page':
return MaterialPageRoute(
builder: (_) =>
FirstPage()); // FirstPage - is just a Widget with your content
case 'second_page':
return MaterialPageRoute(
builder: (_) => SecondPage()); // Also custom Widget
//... other random or not pages
}
}
}
class StartPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Start page'),
),
body: Column(
children: [
Expanded(
child: ListView(children: <Widget>[
Card(
child: ListTile(
leading: Text('🐔'),
title: Text('Chicken'),
onTap: () {
Navigator.of(context)
.pushNamed(RouteGenerator.getRandomNameOfRoute());
},
),
),
]),
),
Center(
child: RaisedButton(
child: Text('Go to random page'),
onPressed: () => Navigator.of(context)
.pushNamed(RouteGenerator.getRandomNameOfRoute()),
),
),
],
));
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text("First Page");
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text("Second Page");
}
}
Try removing the const before the on the ListView children.
Can someone explain why not printing efeioi when it is back from pageE?
Page A
Navigator.pushNamed(context, PageB.ROUTE).then((onValue) {
print("efeioi");
});
Page B
Navigator.of(context)
.pushReplacementNamed(PageC.ROUTE, arguments: onValue);
PageC
Navigator.pushNamed(context, PageD.ROUTE,
arguments: onValue);
PageD
Navigator.pop(context); // back to Page C
Page C
Navigator.pushNamed(context, PageE.ROUTE,
arguments: onValue);
Page E
Navigator.of(context).popUntil(ModalRoute.withName(PageA.ROUTE));
I can't use Navigator.pop in Page E because it will back to Page C!
I have uploaded full code here
https://github.com/tony123S/navigation
As per your requirement I have implemented as below
main.dart
initState : this will be called when you navigate from E to A
refreshPage : it will not called as you already popped before returning to A Page
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: A(),
routes: <String, WidgetBuilder>{
'/A': (BuildContext context) => new A(),
'/B': (BuildContext context) => new B(),
'/C': (BuildContext context) => new C(),
'/D': (BuildContext context) => new D(),
'/E': (BuildContext context) => new E(),
},
);
}
}
class A extends StatefulWidget {
#override
_FirstRouteState createState() => _FirstRouteState();
}
class _FirstRouteState extends State<A> {
final String fromPage;
_FirstRouteState({Key key, #required this.fromPage});
#override
void initState() {
// TODO: implement initState
super.initState();
print("Called askdfjaksdfj");
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page A'),
),
body: Center(
child: RaisedButton(
child: Text('Open B'),
onPressed: () {
// Navigate to second route when tapped.
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => B()),
// );
Navigator.push(
context,
MaterialPageRoute(builder: (context) => B()),
).then((res) => refreshPage());
},
),
),
);
}
refreshPage() {
print("refresh page is called");
}
}
class B extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("B Page"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
Navigator.of(context).pushNamed(
"/C",
);
},
child: Text('Go to C'),
),
),
);
}
}
class C extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("C Page"),
),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
Navigator.pushNamed(
context,
"/D",
);
},
child: Text('Go to D'),
),
RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
Navigator.pushNamed(
context,
"/E",
);
},
child: Text('Go to E'),
),
],
),
),
);
}
}
class D extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("D Page"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
Navigator.pop(context);
},
child: Text('Go back to C'),
),
),
);
}
}
class E extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("E Page"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigator.pop(context);
// Navigator.of(context).pushNamed("/A");
// Navigator.of(context).popUntil(ModalRoute.withName('/A'));
Navigator.of(context)
.pushNamedAndRemoveUntil('/A', (Route<dynamic> route) => false,);
},
child: Text('Go to A'),
),
),
);
}
}
Please run code for better understanding and reply if you found any difficulty
Noob here.
I've made a update checker with flutter, but if I choose any button, it give me black screen.
How can I fix this? Any ideas?
Code
Full Source : https://github.com/aroxu/LiteCalculator
Dialog Part Source :
import 'package:LiteCalculator/updater/bean/UpdaterBean.dart';
import 'package:flutter/material.dart';
class UpdateHolder extends StatelessWidget {
final List<Version> version;
UpdateHolder({Key key, this.version}) : super(key: key);
#override
Widget build(BuildContext context) {
return calculateResult(
version[0].latestVersion, version[1].currentVersion, context);
}
Widget calculateResult(latestVersion, currentVersion, context) {
print('Latest Version : ${int.parse(latestVersion)}');
print('Current Version : ${int.parse(currentVersion)}');
Widget data;
if ((int.parse(currentVersion) <= int.parse(latestVersion))) {
data = Center(
child: createAlert('Update Required', actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
print('OK Button Pressed.');
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('Later'),
onPressed: () {
print('Later Button Pressed.');
Navigator.of(context).pop();
},
),
]),
);
} else
data = Center();
return data;
}
Widget createAlert(content, {List<Widget> actions, title}) {
AlertDialog snackBar;
snackBar = AlertDialog(
content: Text(content),
actions: actions,
);
return snackBar;
}
}
call this for your popup,
void showDialogPopup(){
showDialog(
context: context,
builder: (_)=>AlertDialog(
backgroundColor: Colors.transparent,
content: Container(
child: Center(
child: FlatButton(
onPressed: (){
Navigator.of(context).pop(null);
},
child: Center(
child: Text("close")
)
)
)
)
)
);
}
A black screen or a blank screen? If its a black screen, your are not wrapping your main widget (which goes in the runApp) with a MaterialApp.
You can refer this.
I used url_launcher 5.4.1 to open PlayStore web.
import "package:flutter/material.dart";
import 'package:url_launcher/url_launcher.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: FirstPage(),
debugShowCheckedModeBanner: false,
);
}
}
class FirstPage extends StatefulWidget {
#override
_FirstPageState createState() => _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
#override
void initState() {
_checkUpdate();
super.initState();
}
Future<void> _checkUpdate() async {
await Future.delayed(Duration.zero);
await showDialog(
context: context,
builder: (context) => UpdateDialog(),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text("First Page"),
),
);
}
}
class UpdateDialog extends StatefulWidget {
#override
_UpdateDialogState createState() => _UpdateDialogState();
}
class _UpdateDialogState extends State<UpdateDialog> {
Future<void> _updateFound;
#override
void initState() {
_updateFound = _checkForUpdate();
super.initState();
}
Future<bool> _checkForUpdate() async {
await Future.delayed(Duration.zero);
bool updateFound = false;
await Future.delayed(Duration(seconds: 3)); // Do Get call to server
updateFound = true;
if (!updateFound) Navigator.pop(context);
return updateFound;
}
Future<void> _openWebPage() async {
Navigator.pop(context);
launch("https://play.google.com"); //Your link `url_launcher` package
}
void _laterClicked(){
Navigator.pop(context);
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _updateFound,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
CircularProgressIndicator(),
const SizedBox(height: 12.0),
Text("Checking for Update"),
],
),
);
else if (snapshot.hasError)
return AlertDialog(
title: Text("Error Occured"),
content: Text("ERROR: ${snapshot.error}"),
);
else if(snapshot.data)
return AlertDialog(
title: Text("Update Required"),
content: Text(
"Latest version found. Need an update. bla bla bla bla bla bla"),
actions: <Widget>[
FlatButton(
child: Text("OK"),
onPressed: _openWebPage,
),
FlatButton(
child: Text("LATER"),
onPressed: _laterClicked,
),
],
);
else
return const SizedBox();
},
);
}
}
This happens whenever you try to pop using the Widget's context.
In the following code:
FlatButton(
child: Text('OK'),
onPressed: () {
print('OK Button Pressed.');
Navigator.of(context).pop();
},
)
context represents the context of the widget, itself (provided in the build method).
To resolve this issue instead of creating a Dialog widget and returning it as the main widget, just use showDialog and return a simple Container().
Use dialogContext to pop the dialog and not the widget itself.
for example:
if ((int.parse(currentVersion) <= int.parse(latestVersion))) {
showDialog(
builder: (dialogContext) => AlertDialog(
content: Text('Update Required'),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
print('OK Button Pressed.');
Navigator.of(dialogContext).pop();
},
),
FlatButton(
child: Text('Later'),
onPressed: () {
print('Later Button Pressed.');
Navigator.of(dialogContext).pop();
},
),
],
),
);
}
return Container();
I had a similar problem and my solution was something like that:
bool hasBeenShown = false;
if(!hasBeenShown) {
Navigator.pop(context);
}
hasBeenShown = true;
The problem for me was that for some reason Navigator.pop been invoked multiple times when it's supposed to be invoked only once.
Is it possible to return to the exact same place meaning state wise in flutter while using this?
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ConnectHome(user:widget.user))));
We have cards on the home screen "ConnectHome()" and we need to return them to the same spot.
You can copy paste run full code below
You can await Navigator.push and In Navigator.pop include UserObject()
You can see the code continue execution and print UserObject()
code snippet
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => ConnectHome()),
);
print('result ${result.name}')
...
Navigator.pop(context, UserObject("hello","world"));
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Returning Data',
home: HomeScreen(),
));
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Returning Data Demo'),
),
body: Center(child: SelectionButton()),
);
}
}
class SelectionButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: Text('Pick an option, any option!'),
);
}
// A method that launches the SelectionScreen and awaits the result from
// Navigator.pop.
_navigateAndDisplaySelection(BuildContext context) async {
// Navigator.push returns a Future that completes after calling
// Navigator.pop on the Selection Screen.
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => ConnectHome()),
);
print('result ${result.name}');
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("${result.name}")));
}
}
class UserObject {
String name;
String id;
UserObject(this.name, this.id);
}
class ConnectHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pick an option'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Yep!" as the result.
Navigator.pop(context, UserObject("hello","world"));
},
child: Text('Hello'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Nope!" as the result.
Navigator.pop(context, UserObject("no","No"));
},
child: Text('No.'),
),
)
],
),
),
);
}
}
I have 2 pages, in the first page I have a button which is on click will open second page, in second page I have variable number = 999; so when I back to the first page I want to show the number print(number); or display on Text(number) How to do it with dispose() ?
#override
void dispose() {
super.dispose();
// send data to the first page
}
thanks for your answer
You can simply do this with the help of a navigator.
Navigator.push returns a Future that completes after calling
Navigator.pop on the Second Screen with the value passed.
e.x code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Returning Data',
home: HomeScreen(),
));
}
class HomeScreen extends StatelessWidget {
String _resultNumber = '';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Returning Data Demo'),
),
body: Center(child: SelectionButton()),
);
}
}
class SelectionButton extends StatefulWidget {
#override
_SelectionButtonState createState() => _SelectionButtonState();
}
class _SelectionButtonState extends State<SelectionButton> {
String _resultNumber;
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RaisedButton(
onPressed: () => _navigateAndDisplaySelection(context),
child: Text('Pick an option, any number!'),
),
Text(_resultNumber ?? ''),
]);
}
_navigateAndDisplaySelection(BuildContext context) async {
// Navigator.push returns a Future that completes after calling
// Navigator.pop on the Selection Screen.
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
_resultNumber = result;
}
}
class SelectionScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pick a number'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Yep!" as the result.
Navigator.pop(context, '999');
},
child: Text('999 Number'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Nope!" as the result.
Navigator.pop(context, '500');
},
child: Text('550 Number'),
),
)
],
),
),
);
}
}
With dispose() you need override the back pressed, to do this wrap the Scaffold in WillPopScope widget.
return WillPopScope(
onWillPop: () {
_backPressed();
return Future.value(false);
},
child: Scaffold(
appBar: AppBar(
title: Text('your text'),
),
body: Center(),
),
);
void _backPressed() {
Navigator.pop(context, '999');
}