showModalBottomSheet Function onClose - flutter

I want to add a function when the showModalBottomSheet is close or when the barrier tapped the function run(routing to the main page) but how?
I want to run this when the barrier tapped/modal closed
Navigator.pushNamedAndRemoveUntil(context, '/mainMenuPage', (route) => false);
Modal Code
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(25.0),
),
),
backgroundColor: Colors.white,
context: context,
builder: (context) => Widget(...),
);
}

Try below code hope its help to you.
Your Widget with bottomSheet:
Center(
child: ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Modal BottomSheet'),
],
), //MyWidget()
),
);
},
).then(
(value) => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyWidget(),
),
),
);
},
),
),
Other class:
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Center(
child: Text(
'Hello, World!',
style: Theme.of(context).textTheme.headline4,
),
),
);
}
}
.then() -> This means that the next instructions will be executed. But it allows you to execute the code when the asynchronous method completes.

showModalBottomSheet(
context: context,
builder: (context){
return Text("example");
}
).then((value) => {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => const Page2()))
});
You can try like this.

Related

The device's exit button does not exit the app in flutter

i added willpopscope with back function In this project i added the exit code, but the app didn't end; instead it went to the homepage and I made this initial screen to start the project with all the details running in the homepage screen.
I want to exit from device but its not working Can somebody tell me what the problem is?
#override
Widget build(BuildContext context) {
Future<bool> _back() {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Do you want to exit this app?"),
actions: <Widget>[
TextButton(
child: const Text('ok',style: TextStyle(fontSize: 15,color: Colors.indigo),),
onPressed: () {
Navigator.of(context).pop(true);
},
),
TextButton(
child: const Text('no',style: TextStyle(fontSize: 15,color: Colors.indigo),),
onPressed: () {
Navigator.of(context).pop(false);
},
),
],
);
}
).then((value) => value ?? false);
}
return WillPopScope(
onWillPop: _back,
child: SafeArea(
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container(
child: Padding(
padding: const EdgeInsets.all(80.0),
child: Column(
children: <Widget>[
Container(
Row(
children: <Widget>[
SizedBox(
height: 80,
width: 150,
child: OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(
width: 3.0, color: Colors.indigo.shade900),
backgroundColor: Colors.transparent,
shape: const StadiumBorder()),
child: Text(
"LETS START",
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute( builder: (context) => homepage(langname: '',))); },
),
),
],
),
],
),
)),
)),
),
);
}
}
You can do Like this:
var currentBackPressTime;
Future<bool> onWillPop() {
DateTime now = DateTime.now();
if (currentBackPressTime == null ||
now.difference(currentBackPressTime) > Duration(seconds: 2)) {
currentBackPressTime = now;
Fluttertoast.showToast(msg: "Press Again to Exit!");
return Future.value(false);
} else {
exit(0);
// SystemChannels.platform.invokeMethod('SystemNavigator.pop');
return Future.value(false);
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: onWillPop,
child: Scaffold(
--------------

BottomSheet value does not update using button flutter

I have a Bottom Sheet which has sets of buttons. I use the buttons to change the value of pinString and a text to show the pinString. The value of the text does not update when button is clicked. How to fix this
showNumberPad(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (context) {
return StatefulBuilder(builder: (context, setState) {
return Container(
height: 550.0,
child: Column(
children: <Widget>[
Text(
"$pinString",
),
KeyboardNumber(
n: 1,
onPressed: () {
pinIndexSetup("1");
setState1() {
pinString = "New Pin";
}
},
),
],
),
);
});
},
);
}
KeyboardNumber is a custom Stateful widget where I want to pass the onPressed as a parameter.
Code for keyboardNumber:
class KeyboardNumber extends StatefulWidget {
final int n;
final onPressed;
const KeyboardNumber({Key key, this.n, this.onPressed}) : super(key: key);
#override
_KeyboardNumberState createState() => _KeyboardNumberState();
}
class _KeyboardNumberState extends State<KeyboardNumber> {
#override
Widget build(BuildContext context) {
return Container(
width: 60.0,
height: 60.0,
decoration: BoxDecoration(
color: teal2,
borderRadius: BorderRadius.all(
Radius.circular(10),
),
),
alignment: Alignment.center,
child: FlatButton(
padding: EdgeInsets.all(8.0),
onPressed: widget.onPressed,
height: 90.0,
child: Text(
"${widget.n}",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
);
}
}
you define pinString in another state and change it in bottomeSheet state, you must define it in this line :
showModalBottomSheet(
context: context,
builder: (context) {
String pinString = 'hi';
return StatefulBuilder(builder: (BuildContext context, StateSetter setState){
return Container(
height: 550.0,
child: Column(
children: <Widget>[
Text(
"$pinString",
),
FlatButton(
child: Text("Update"),
onPressed: () {
setState(() => pinString = 'new');
},
),
],
),
);
});
},
);
}
Please note that the new setState will override your main widget setState but sure you can just rename it so you would be able to set state of your parent widget and the modal's
Here is the updated code.
showNumberPad(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (context) {
return StatefulBuilder(builder: (context, SetState1) {
return Container(
height: 550.0,
child: Column(
children: <Widget>[
Text(
"$pinString",
),
FlatButton(
child: Text("Update"),
onPressed: () {
SetState1(() {
pinString = "New Pin";
});
},
),
],
),
);
});
},
);
}

How to call flutter dialog from separate class?

I need to separate my dialog to separate widgets an call from anywhere on some button click. Now my code looks like:
import 'package:flutter/material.dart';
class PlacesListScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return _Map();
}
}
class _Map extends StatefulWidget {
#override
_MapState createState() => _MapState();
}
class _MapState extends State<_Map> {
final _titleController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('App name'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text(
"Dialog title",
textAlign: TextAlign.center,
),
content: TextField(
decoration: InputDecoration(labelText: 'Title'),
controller: _titleController,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => StatefulBuilder(builder:
(BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text(
"Second subdialog title",
textAlign: TextAlign.center,
),
content: Container(
width: 150,
height: 200,
decoration: BoxDecoration(
border:
Border.all(width: 1, color: Colors.grey),
),
child: Text('Here will be file'),
alignment: Alignment.center,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () => Text('Here I will work with state'),
child: Text("Yes"),
),
],
);
}),
);
},
child: Text("Yes"),
),
],
),
);
},
),
],
),
body: Text('App body here'),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FloatingActionButton(
onPressed: () => Text('Here will be called dialog function'),
child: Icon(Icons.add, color: Colors.white),
backgroundColor: Colors.green,
heroTag: 'mapZoomIn',
),
],
),
);
}
}
Now how I can this part of code (calling dialog) separate to another widget and call then using created widget.
showDialog(
context: context,
builder: (ctx) => StatefulBuilder(builder:
(BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text(
"Second subdialog title",
textAlign: TextAlign.center,
),
content: Container(
width: 150,
height: 200,
decoration: BoxDecoration(
border:
Border.all(width: 1, color: Colors.grey),
),
child: Text('Here will be file'),
alignment: Alignment.center,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () => Text('Here I will work with state'),
child: Text("Yes"),
),
],
);
}),
);
Firstly, you can refactor your StatefulBuilder(builder: (BuildContext context, StateSetter setState) { return AlertDialog(... into one separate widget like MyFancyDialog extends StatefulWidget. Then just call showDialog(..., MyFancyWidget()) when you need it.
Secondly, if you do not want the first method, you can extract the whole showDialog(...) into a function like void showMyFancyDialog() { showDialog... }. Is it also OK, since in dart functions are first class.
Did you try to create a new Stateful widget class at the bottom of your code and try to call that widget? If you didn't try that,
Go to under of your code and create a new Stateful class. (Let's say that myDialog)
Add the code that you want to call, inside of your "myDialog" widget
Go for where you want to call that code and try to call that class.
Hope this works for you.
Create a separate file. Import material package.
then create "Widget myDialog(context){ // paste your showDialog code here }"
Now your myDialog widget has been ready for using anywhere on whole project just import and call it.
When you call it pass BuildContext in its argument.
Its work for me.

How to deal with setState properly

void showSimpleCustomDialog(BuildContext context, String listName) async{
if(randList.isEmpty){
randList = await theDb.queryWhere("$listName");
}else{
randList.clear();
randList = await theDb.queryWhere("$listName");
}
setState((){
});
String randValue = "Click generate new to get a random value";
Dialog simpleDialog = Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
child: Text(
"$randValue"
),
),
Padding(
child: Row(
children: <Widget>[
RaisedButton(
color: Colors.blue,
onPressed: ()
String lol = randList[0 + rng.nextInt(randList.length - 0)].getItem();
print(randValue);
setState(() {
randValue = lol;
});
},
child: Text(
'generate new',
style: TextStyle(fontSize: 18.0, color: Colors.white),
),
)
],
),
),
],
),
),
);
showDialog(
context: context, builder: (BuildContext context) => simpleDialog);}
When I am clicking on "generate new" button I want to update my randomValue and to display that randomValue as Text Widget. To do that dynamically Im using setState, but it is not working, and i dont understand why. Please help me.
You should use StatefulBuilder with dialogue.
showDialog(
context: context,
builder: (context) {
String contentText = "Content of Dialog";
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text("Title of Dialog"),
content: Text(contentText),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text("Cancel"),
),
FlatButton(
onPressed: () {
setState(() {
contentText = "Changed Content of Dialog";
});
},
child: Text("Change"),
),
],
);
},
);
},

How did i setup popup AlertDialog?

How did i setup popup AlertDialog when int is equal or greater than 100?
showDialog(
context: _context,
builder: (BuildContext context) => AlertDialog(
title: Text("$_winner Won"),
)
);
void scoreTeamA() {
setState(() {
outputTeamA += _choiceA;
});
}
// I would like to show outputTeamA on the AlertDialog
Thank you
Mohammad
One way is to create a Widget for the AlertDialog and pass the String/Widget you want to show on that dialog.
class LoadingDialog{
static Future<void> showLoadingDialog(BuildContext context,String text) async {
return showDialog(
context: context,
builder: (BuildContext context){
return SimpleDialog(
children: <Widget>[
Center(
child: Container(
child: Column(
children: <Widget>[
SizedBox(
height:10,
),
Text(text),
]
),
),
),
],
),
}
);
}
}
then you can call on an Event like:
void scoreTeamA(){
outputTeamA += _choiceA;
LoadingDialog.showLoadingDialog(context, outputTeamA);
}
Note: this code might have some errors. i haven't tested this.
This is how I display an AlertDialog
showAlertDialog() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
side: BorderSide(color: Colors.redAccent, width: 2.0),
),
elevation: 6,
titlePadding: EdgeInsets.all(8.0),
titleTextStyle: TextStyle(
fontSize: 18, color: Colors.red, fontWeight: FontWeight.bold),
title: Text(
'This is the alert title',
textAlign: TextAlign.center,
),
contentPadding: EdgeInsets.all(8.0),
contentTextStyle: TextStyle(fontSize: 14, color: Colors.black),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Content...')
//content goes here
],
),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(), child: Text('Okay'))
],
),
);
}
And then you would do your if check to check
if( outputTeamA >= 100){
showAlertDialog();
}
Of course you could use outputTeamA in AlertDialog