i'm trying to show the data i retrieve on a function outside of it (to show in a listview of products) but i cant do it because i cant access the variable.
First I open a dialog where i put the order number, when i click a button on this dialog it runs the following code:
(this function is inside a onPressed).
Future loadProdutos() async{
ProdutosList produtosList =
ProdutosList.fromJson(response.data);
print(produtosList.produtos[1].qtd);
print(produtosList.produtos.length);
}
setState(() {
loadProdutos();
Navigator.pop(context, true);
});
So the data its stored on produtoslist, but when I try to use the produtosList length on the listview (for example) like the example below it cant access the data.
Here
child: ListView.builder(
itemCount: produtosList.produtos.length, <<< //Undefined name 'produtosList'.
Try correcting the name to one that is defined, or defining the name.dart(undefined_identifi
How can I make produtosList accessable from the whole file?
Or to create it outside of the function and use it inside (when i try i cant access the variable inside of the function, maybe because its async).
Heres the full code
class OS extends StatefulWidget {
#override
_OSState createState() => _OSState();
}
class _OSState extends State<OS> {
static _read() async {
final prefs = await SharedPreferences.getInstance();
final key = 'operador';
final value = prefs.getString(key);
print('saved tester $value');
String operadorLogado = value;
return operadorLogado;
}
#override
final _numeroOsController = TextEditingController();
void initState() {
super.initState();
_read();
var produtosList1 = <ProdutoOs>[];
//WidgetsBinding.instance.addPostFrameCallback((_) => _read());
// final prefs = await SharedPreferences.getInstance();
// final key = 'usuario';
// final value = prefs.getString(key);
// print('saved $value');
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("OS Nº xxx"),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
scrollable: true,
title: Text('BUSCAR OS'),
content: Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
child: TextFormField(
controller: _numeroOsController,
decoration: InputDecoration(
icon: Icon(Icons.search),
),
),
),
),
actions: [
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.blue,
onPrimary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32.0),
),
),
child: Text("IR"),
onPressed: () async {
Response response;
Dio dio = new Dio();
String url =
'http://192.168.15.2:8090/api/getOs';
response = await dio.post(url, data: {
"numeroos": _numeroOsController.text
});
print(response.statusCode);
jsonDecode(response);
Future loadProdutos() async {
ProdutosList produtosList =
ProdutosList.fromJson(response.data);
print(produtosList.produtos[1].qtd);
print(produtosList.produtos.length);
}
setState(() {
loadProdutos();
Navigator.pop(context, true);
});
},
)
]);
});
},
child: Icon(
Icons.search,
size: 26.0,
),
)),
],
),
body: Column(
children: [
Container(
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
children: [
Expanded(
flex: 8,
child: Text(
"CLIENTE:",
style: TextStyle(color: Colors.white),
),
),
Expanded(
flex: 8,
child: Text(
"STATUS:",
style: TextStyle(color: Colors.white),
),
),
],
),
),
),
Container(
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 8.0, 0, 8.0),
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Text("CÓDIGO",
style: TextStyle(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis),
),
Expanded(
flex: 1,
child: Text(
"QTD",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Expanded(
flex: 3,
child: Text(
"FUNCIONÁRIO",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Expanded(
flex: 4,
child: Text(
"DESCRIÇÃO",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
],
),
),
),
Divider(
height: 5.0,
),
Expanded(
child: ListView.builder(
itemCount: 3,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 4.0, 0.0, 4.0),
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Text(
"12345",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Expanded(
flex: 1,
child: Text(
"12",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Expanded(
flex: 3,
child: Text("example",
style: TextStyle(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis
),
),
Expanded(
flex: 4,
child: Text(
"DESCRIÇÃO DA PEÇA XXXXXX11111111 XXXXXXX",
style: TextStyle(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis),
),
],
),
);
}),
)
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
scrollable: true,
title: Text('ADICIONAR PEÇA'),
content: Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
icon: Icon(Icons.search),
),
),
],
),
),
),
actions: [
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.blue,
onPrimary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32.0),
),
),
child: Text("IR"),
onPressed: () {
// your code
}),
],
);
});
},
child: Icon(Icons.add)),
);
}
}
Declare a local variable in class.
For example:
class PhotosScreen {
final photos = <Photo>[];
Future<void> reloadPhotos() async {
photos.clear();
photos.addAll(await api.getPhotos());
setState(() {});
}
}
In your case (you placed a variable to method, not to class):
var produtosList1 = <ProdutoOs>[];
#override
final _numeroOsController = TextEditingController();
void initState() {
super.initState();
}
Related
I'm making a food ordering app in which I want to provide a discount feature. I've implemented most of the part but I'm getting stuck at a point where I basically want to update the totalAmount with the discountRate.
class CartScreen extends StatefulWidget
{
final String? sellerUID;
const CartScreen({super.key, this.sellerUID});
#override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen>
{
List<int>? separateItemQuantityList;
num totalAmount = 0;
final _couponText = TextEditingController();
#override
void initState() {
super.initState();
totalAmount = 0;
Provider.of<TotalAmount>(context, listen: false).displayTotalAmount(0);
separateItemQuantityList = separateItemQuantities();
}
#override
Widget build(BuildContext context) {
var _coupon = Provider.of<CouponProvider>(context);
double discountRate = _coupon.discount/100;
return Scaffold(
appBar: AppBar(
title: const Text("Cart"),
flexibleSpace: Container(decoration: BoxDecoration(color: myColor),),
automaticallyImplyLeading: true,
),
body: CustomScrollView(
slivers: [
//display cart items with quantity number
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("items")
.where("itemID", whereIn: separateItemIDs())
.orderBy("publishedDate", descending: true)
.snapshots(),
builder: (context, snapshot)
{
return !snapshot.hasData
? SliverToBoxAdapter(child: Center(child: circularProgress(),),)
: snapshot.data!.docs.isEmpty
? const SliverToBoxAdapter(child: Center(child: Padding(
padding: EdgeInsets.only(top: 300),
child: Text("The cart is empty",style: TextStyle(
fontSize: 24, fontWeight: FontWeight.bold),),
)))
: SliverList(
delegate: SliverChildBuilderDelegate((context, index)
{
Items model = Items.fromJson(
snapshot.data!.docs[index].data()! as Map<String, dynamic>,
);
if(index == 0)
{
totalAmount = 0;
totalAmount = totalAmount + (model.price! * separateItemQuantityList![index]);
}
else
{
totalAmount = totalAmount + (model.price! * separateItemQuantityList![index]);
}
if(snapshot.data!.docs.length - 1 == index)
{
WidgetsBinding.instance.addPostFrameCallback((timeStamp)
{
Provider.of<TotalAmount>(context, listen: false).displayTotalAmount(totalAmount.toDouble());
});
}
return CartItemDesign(
model: model,
context: context,
quanNumber: separateItemQuantityList![index],
);
},
childCount: snapshot.hasData ? snapshot.data!.docs.length : 0,
),
);
},
),
SliverFillRemaining(
hasScrollBody: false,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: const Color(0xfffb9e5a).withOpacity(0.6),
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
),
width: double.infinity,
height: 160,
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 12, 8, 6),
child: Column(
children: [
Consumer2<TotalAmount, CartItemCounter>(builder: (context, amountProvider, cartProvider, c){
return Center(
child: cartProvider.count == 0
? const Text("Please add something in the cart", style: TextStyle(fontSize: 18),)
: Column(
children: [
Text("The total amount is ₹${amountProvider.tAmount.toString()}", style: const TextStyle(fontSize: 18)),
const SizedBox(height: 10,),
Container(
height: 50,
width: MediaQuery.of(context).size.width * 8,
decoration: BoxDecoration(
border: Border.all(color: myColor, width: 1,),
borderRadius: const BorderRadius.all(Radius.circular(20)),
color: Colors.white54
//color: Colors.white54
),
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 15),
child: TextField(
controller: _couponText,
maxLines: 1,
decoration: const InputDecoration.collapsed(
hintText: 'Apply coupon here ...'
),
),
),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: ElevatedButton(
onPressed: (){
_coupon.getcouponDetails(_couponText.text).then((value) {
if(value.data() == null){
setState(() {
_coupon.discount = 0;
});
showCodeDialog(_couponText.text, 'not valid');
return;
}
if(_coupon.expired==false){
// Code to be done here.
Fluttertoast.showToast(msg: 'Coupon is valid');
// I want to update the totalAmount value with the discountRate here...
}
if(_coupon.expired==true){
setState(() {
_coupon.discount = 0;
});
showCodeDialog(_couponText.text, 'expired');
return;
}
});
},
style: ElevatedButton.styleFrom(
textStyle: const TextStyle(
fontSize: 15,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
)
),
child: const Text('Apply'),
),
),
],
),
),
const SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
onPressed: (){
clearCartNow(context);
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (c) => const HomeScreen()));
Fluttertoast.showToast(msg: "Cart cleared");
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black, backgroundColor: myColor
),
icon: const Icon(Icons.clear_all),
label: const Text("Clear")),
ElevatedButton.icon(
onPressed: (){
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (c)=> AddressScreen(
totalAmount: totalAmount.toDouble(),
sellerUID: widget.sellerUID,
),
),
);
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black,
backgroundColor: myColor,
),
icon: const Icon(Icons.navigate_next),
label: const Text("Proceed")),
],
)
],
),
);
}),
],
),
)
),
),
)
],
),
);
}
showCodeDialog(code, validity){
showCupertinoDialog(
context: context,
builder: (BuildContext context){
return CupertinoAlertDialog(
title: const Text('Apply Coupon'),
content: Text('This discount coupon $code you have entered is $validity'),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: (){Navigator.pop(context);},
child: Text('Ok', style: TextStyle(color: Colors.white),),
),
)
],
);
});
}
}
I tried changing the totalAmount, amountProvider.tAmount and their types, but nothing is working for me.
In this image, the total amount is without discount. If I apply a coupon of 10%, the total amount should be subtracted by 10%.
I can add more information if required.
I want the dialog to open when a button is clicked, but an error occurs due to BLoC. Previously, there was such an error with the class itself, but I successfully solved it, and in this case, the complexity already arises. I've already tried a couple of options but couldn't solve it. I tried to make the event in onPressed as a separate widget, and the same error did not work either.
home_page
class HomePage extends StatelessWidget {
final todoRepository = TodoRepository();
#override
Widget build(BuildContext context) {
// final TodoBloc todoBloc = context.read<TodoBloc>();
return BlocProvider<TodoBloc>(
create: (context) => TodoBloc(todoRepository),
child: Scaffold(
appBar: AppBar(
title: const Text('Flutter Todos'),
),
// floatingActionButton: FloatingActionButton(
// onPressed: () {
// // _addTodo(context);
// final newTodo = Todo(description: 'Todo 1');
// BlocProvider.of<TodoBloc>(context).add(CreateTodos(newTodo));
// },
// child: const Icon(Icons.add),
// ),
body: SingleChildScrollView(
child: Column(
// crossAxisAlignment: CrossAxisAlignment.center,
children: [
// ActionButton(),
TodoList(),
],
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add, size: 32, color: Colors.black),
onPressed: () {
// showAddTodoSheet(context);
// showAddTodoSheet(BuildContext context) {
final TodoBloc todoBloc = context.read<TodoBloc>();
final _todoDescriptionFromController = TextEditingController();
showModalBottomSheet(
context: context,
builder: (builder) {
return BlocBuilder<TodoBloc, TodoState>(
builder: (context, state) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
color: Colors.transparent,
child: Container(
height: 230,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0))),
child: Padding(
padding: const EdgeInsets.only(
left: 15, top: 25.0, right: 15, bottom: 30),
child: ListView(
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextFormField(
controller:
_todoDescriptionFromController,
textInputAction:
TextInputAction.newline,
maxLines: 4,
style: const TextStyle(
fontSize: 21,
fontWeight: FontWeight.w400),
autofocus: true,
decoration: const InputDecoration(
hintText: 'I have to...',
labelText: 'New Todo',
labelStyle: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.w500)),
validator: (value) {
if (value!.isEmpty) {
return 'Empty description!';
}
return value.contains('')
? 'Do not use the # char.'
: null;
},
),
),
Padding(
padding: const EdgeInsets.only(
left: 5, top: 15),
child: CircleAvatar(
backgroundColor: Colors.indigoAccent,
radius: 18,
child: IconButton(
icon: const Icon(
Icons.save,
size: 22,
color: Colors.white,
),
onPressed: () {
final newTodo = Todo(
description:
_todoDescriptionFromController
.value.text);
if (newTodo
.description.isNotEmpty) {
todoBloc
.add(CreateTodos(newTodo));
Navigator.pop(context);
}
},
),
),
)
],
),
],
),
),
),
),
);
});
});
},
),
));
}
You have to use MultiBlocProvider before MaterialApp.
just do like that
#override
Widget build(BuildContext context) => MultiBlocProvider(
providers: [
BlocProvider(create: (_) => TodoBloc()),
],
child: MaterialApp()
);
I am developing an app with a dropdown. Below is my code. I have removed the UI design code to isolate the dropdown section itself.
class ShoppingCartUIState extends State<ShoppingCartUI> {
final _formKey = GlobalKey<FormState>();
String _checkoutDropdownValue=null;
//**UI design Code Removed**//
_showCheckoutPopup() {
String date=DateTime.now().toString();
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0)), //this right here
child: Container(
height: MediaQuery.of(context).size.height/3,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
child: Text(
"What is Your Required Delivery Date?",
style: Theme.of(context).textTheme.subtitle,
),)
],
),
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.calendar_today),
color: Colors.green,
onPressed: () {
date = "111";
},
),
Text(date)
],
),
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(top:20, left:10),
child: Text(
"What is your Airport of delivery?",
style: Theme.of(context).textTheme.subtitle,
),)
],
),
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(top:5, left:10),
child: DropdownButton(
hint: Text(
"Please Select ",
style: TextStyle(
fontSize: 14,
),
),
items: <String>[
'Skinless Boneless, Full Loins',
'brown',
'silver'
].map((data) {
return DropdownMenuItem(
child: new Text(data,
style: Theme.of(context).textTheme.body1),
value: data,
);
}).toList(),
onChanged: (String newValue) {
setState(() {
_checkoutDropdownValue = newValue;
print(newValue);
});
},
value: _checkoutDropdownValue),
)
],
),
],
),
));
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
}
The issue is when I change the dropdown item, the new value never get selected. The previously selected value is always displayed. However since i am using a print when dropdown is done, I can see the item has changed.
How can I solved this issue?
Wrap your Dialog widget with StatefulBuilder to rebuild the dialog.
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: MyPage(), //TODO: Add Scaffold
);
}
}
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
String date = "";
String _checkoutDropdownValue;
_showCheckoutPopup() {
return StatefulBuilder(
builder: (context, setState){
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
), //this r// ight here
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
alignment: Alignment.centerLeft,
child: Text(
"What is Your Required Delivery Date?",
style: Theme.of(context).textTheme.subtitle,
),
),
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.calendar_today),
color: Colors.green,
onPressed: () {
setState(() {
date = "111";
});
},
),
Text(date)
],
),
Container(
margin: EdgeInsets.only(top: 20, left: 10),
alignment: Alignment.centerLeft,
child: Text(
"What is your Airport of delivery?",
style: Theme.of(context).textTheme.subtitle,
),
),
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 5, left: 10),
child: DropdownButton<String>(
hint: Text(
"Please Select ",
style: TextStyle(
fontSize: 14,
),
),
items: <String>[
'Skinless Boneless, Full Loins',
'brown',
'silver'
].map((data) {
return DropdownMenuItem(
child: new Text(data,
style: Theme.of(context).textTheme.body1),
value: data,
);
}).toList(),
onChanged: (String newValue) {
setState(() {
_checkoutDropdownValue = newValue;
});
},
value: _checkoutDropdownValue,
),
)
],
),
],
),
),
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text("Click Here"),
onPressed: () {
showDialog(
context: context,
builder: (context) => _showCheckoutPopup(),
);
},
),
),
);
}
}
can you change your onPressed to print(_checkoutDropdownValue); instead of print(newValue); that way we can see if there is a problem with the assignment
I am not using any button in alert dialog, so in action how can we prevent the overflow the alert dialog, if am using gesture detector or inkwell to get ontap or onpress function or is there any other method to do it
_showDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return UnicornAlertDialog(
title: Column(
children: <Widget>[
Container(
child: Image.asset('images/done.png'),
),
const SizedBox(height: 15.0),
Container(
child: Text(
'Verify',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
)
],
),
content: Text('You have successfully verified your mobile number',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 15.0)),
gradient: LinearGradient(
colors: <Color>[
Color(0xDD4a00e0),
Color(0xFF8e2de2),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
actions: <Widget>[
Container(
child: new GestureDetector(
onTap:(){
Navigator.push(context,
MaterialPageRoute(builder: (context) => ThirdRoute()));
} ,
),
),
]
);
});
}
You are getting overflow error due to GestureDetector used inside actions property of the dialog. If you just want user to tap anywhere on the alertDialog, you can wrap the AlertDialog with GestureDetector. With this, when user taps anywhere on the dialog, it will navigate them to thirdRoute. Working code below:
_showDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return GestureDetector(
child: AlertDialog(
title:
Column(
children: <Widget>[
Container(
child: Image.asset('images/done.png'),
),
const SizedBox(height: 15.0),
Container(
child: Text(
'Verify',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
),
),
)
],
),
content:
Text('You have successfully verified your mobile number',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black, fontSize: 15.0)),
// gradient: LinearGradient(
// colors: <Color>[
// Color(0xDD4a00e0),
// Color(0xFF8e2de2),
// ],
// begin: Alignment.topCenter,
// end: Alignment.bottomCenter,
// ),
actions: <Widget>[]
),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => NextScreen()));
}
);
});
}
Hope this answers your question.
_showDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return GestureDetector(
child: UnicornAlertDialog(
title: Column(
children: <Widget>[
Container(
child: Image.asset('images/done.png'),
),
const SizedBox(height: 15.0),
Container(
child: Text(
'Verify',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
)
],
),
content: Text(
'You have successfully verified your mobile number',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 15.0)),
gradient: LinearGradient(
colors: <Color>[
Color(0xDD4a00e0),
Color(0xFF8e2de2),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
actions: <Widget>[ ]),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => ThirdRoute()));
},
);
});
}
Unicorn alert dialog is used for background-color decoration, and since you cannot have gradient color in normal alert dialog, I used this.
code snippet
_showDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return UnicornAlertDialog(
title: GestureDetector(
onTap: () { print("on tap title");},
child: Column(
children: <Widget>[
Container(
child: Image.asset('assets/images/background.jpg'),
),
const SizedBox(height: 15.0),
Container(
child: Text(
'Verify',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
)
],
),
),
content: GestureDetector(
onTap: () { print("on tap content");},
child: Text('You have successfully verified your mobile number',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 15.0)),
),
gradient: LinearGradient(
colors: <Color>[
Color(0xDD4a00e0),
Color(0xFF8e2de2),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
actions: <Widget>[
]
);
});
}
full code
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
class UnicornAlertDialog extends StatelessWidget {
const UnicornAlertDialog({
Key key,
#required this.gradient,
this.title,
this.titlePadding,
this.titleTextStyle,
this.content,
this.contentPadding = const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0),
this.contentTextStyle,
this.actions,
this.backgroundColor,
this.elevation,
this.semanticLabel,
this.shape,
}) : assert(contentPadding != null),
super(key: key);
final Gradient gradient;
final Widget title;
final EdgeInsetsGeometry titlePadding;
final TextStyle titleTextStyle;
final Widget content;
final EdgeInsetsGeometry contentPadding;
final TextStyle contentTextStyle;
final List<Widget> actions;
final Color backgroundColor;
final double elevation;
final String semanticLabel;
final ShapeBorder shape;
#override
Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(context));
final ThemeData theme = Theme.of(context);
final DialogTheme dialogTheme = DialogTheme.of(context);
final List<Widget> children = <Widget>[];
String label = semanticLabel;
if (title != null) {
children.add(Padding(
padding: titlePadding ?? EdgeInsets.fromLTRB(24.0, 24.0, 24.0, content == null ? 20.0 : 0.0),
child: DefaultTextStyle(
style: titleTextStyle ?? dialogTheme.titleTextStyle ?? theme.textTheme.title,
child: Semantics(
child: title,
namesRoute: true,
container: true,
),
),
));
} else {
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
label = semanticLabel;
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
label = semanticLabel ?? MaterialLocalizations.of(context)?.alertDialogLabel;
}
}
if (content != null) {
children.add(Flexible(
child: Padding(
padding: contentPadding,
child: DefaultTextStyle(
style: contentTextStyle ?? dialogTheme.contentTextStyle ?? theme.textTheme.subhead,
child: content,
),
),
));
}
if (actions != null) {
children.add(ButtonTheme.bar(
child: ButtonBar(
children: actions,
),
));
}
Widget dialogChild = IntrinsicWidth(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: children,
),
);
if (label != null)
dialogChild = Semantics(
namesRoute: true,
label: label,
child: dialogChild,
);
return Dialog(
backgroundColor: backgroundColor,
gradient: gradient,
elevation: elevation,
shape: shape,
child: dialogChild,
);
}
}
class Dialog extends StatelessWidget {
const Dialog({
Key key,
this.gradient,
this.backgroundColor,
this.elevation,
this.insetAnimationDuration = const Duration(milliseconds: 100),
this.insetAnimationCurve = Curves.decelerate,
this.shape,
this.child,
}) : super(key: key);
final Color backgroundColor;
final double elevation;
final Duration insetAnimationDuration;
final Curve insetAnimationCurve;
final ShapeBorder shape;
final Widget child;
final Gradient gradient;
static const RoundedRectangleBorder _defaultDialogShape =
RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0)));
static const double _defaultElevation = 24.0;
#override
Widget build(BuildContext context) {
final DialogTheme dialogTheme = DialogTheme.of(context);
return AnimatedPadding(
padding: MediaQuery.of(context).viewInsets + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0),
duration: insetAnimationDuration,
curve: insetAnimationCurve,
child: MediaQuery.removeViewInsets(
removeLeft: true,
removeTop: true,
removeRight: true,
removeBottom: true,
context: context,
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(minWidth: 280.0),
child: Material(
color: backgroundColor ?? dialogTheme.backgroundColor ?? Theme.of(context).dialogBackgroundColor,
elevation: elevation ?? dialogTheme.elevation ?? _defaultElevation,
shape: shape ?? dialogTheme.shape ?? _defaultDialogShape,
type: MaterialType.card,
child: ClipRRect(
borderRadius: _defaultDialogShape.borderRadius,
child: Container(
decoration: BoxDecoration(
gradient: gradient
),
child: child,
),
),
),
),
),
),
);
}
}
_showDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return UnicornAlertDialog(
title: GestureDetector(
onTap: () { print("on tap title");},
child: Column(
children: <Widget>[
Container(
child: Image.asset('assets/images/background.jpg'),
),
const SizedBox(height: 15.0),
Container(
child: Text(
'Verify',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
)
],
),
),
content: GestureDetector(
onTap: () { print("on tap content");},
child: Text('You have successfully verified your mobile number',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 15.0)),
),
gradient: LinearGradient(
colors: <Color>[
Color(0xDD4a00e0),
Color(0xFF8e2de2),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
actions: <Widget>[
]
);
});
}
Future<void> _ackAlert(BuildContext context) {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Not in stock'),
content: const Text('This item is no longer available'),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
enum ConfirmAction { CANCEL, ACCEPT }
Future<ConfirmAction> _asyncConfirmDialog(BuildContext context) async {
return showDialog<ConfirmAction>(
context: context,
barrierDismissible: false, // user must tap button for close dialog!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Reset settings?'),
content: const Text(
'This will reset your device to its default factory settings.'),
actions: <Widget>[
FlatButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.CANCEL);
},
),
FlatButton(
child: const Text('ACCEPT'),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.ACCEPT);
},
)
],
);
},
);
}
Future<String> _asyncInputDialog(BuildContext context) async {
String teamName = '';
return showDialog<String>(
context: context,
barrierDismissible: false, // dialog is dismissible with a tap on the barrier
builder: (BuildContext context) {
return AlertDialog(
title: Text('Enter current team'),
content: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
autofocus: true,
decoration: new InputDecoration(
labelText: 'Team Name', hintText: 'eg. Juventus F.C.'),
onChanged: (value) {
teamName = value;
},
))
],
),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop(teamName);
},
),
],
);
},
);
}
enum Departments { Production, Research, Purchasing, Marketing, Accounting }
Future<Departments> _asyncSimpleDialog(BuildContext context) async {
return await showDialog<Departments>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return SimpleDialog(
title: const Text('Select Departments '),
children: <Widget>[
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, Departments.Production);
},
child: const Text('Production'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, Departments.Research);
},
child: const Text('Research'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, Departments.Purchasing);
},
child: const Text('Purchasing'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, Departments.Marketing);
},
child: const Text('Marketing'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, Departments.Accounting);
},
child: const Text('Accounting'),
)
],
);
});
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
appBar: AppBar(
title: Text("Dialog"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new RaisedButton(
onPressed: () {
_showDialog(context);
},
child: const Text("Unicon Dialog"),
),
new RaisedButton(
onPressed: () {
_ackAlert(context);
},
child: const Text("Ack Dialog"),
),
new RaisedButton(
onPressed: () async {
final ConfirmAction action = await _asyncConfirmDialog(context);
print("Confirm Action $action" );
},
child: const Text("Confirm Dialog"),
),
new RaisedButton(
onPressed: () async {
final Departments deptName = await _asyncSimpleDialog(context);
print("Selected Departement is $deptName");
},
child: const Text("Simple dialog"),
),
new RaisedButton(
onPressed: () async {
final String currentTeam = await _asyncInputDialog(context);
print("Current team name is $currentTeam");
},
child: const Text("Input Dialog"),
),
],
),
),
);
}
}
void main() {
runApp(new MaterialApp(home: new MyApp()));
}
Hi I have designed a screen in flutter. I have AlertDialog on which I want to close the dialog and screen on pressing. Right now AlertDialog dismiss on press but screen is not closing.
Does anyone know how to do this ?
class ForgotPasswordScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return ForgotPasswordScreenState();
}
}
class ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
var emailController = new TextEditingController();
var authHandler = new Auth();
bool isLoading = false;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
color: Colors.white,
),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Row(
children: <Widget>[
new Expanded(
child: isLoading
? Center(child: CircularProgressIndicator())
: new Container()),
],
),
new Row(
children: <Widget>[
new Expanded(
child: new Padding(
padding: const EdgeInsets.only(left: 40.0),
child: new Text(
"EMAIL",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.redAccent,
fontSize: 15.0,
),
),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin:
const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.redAccent,
width: 0.5,
style: BorderStyle.solid),
),
),
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: TextField(
controller: emailController,
textAlign: TextAlign.left,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'PLEASE ENTER YOUR EMAIL',
hintStyle: TextStyle(color: Colors.grey),
),
),
),
],
),
),
Divider(
height: 24.0,
),
new Container(
width: MediaQuery.of(context).size.width,
margin:
const EdgeInsets.only(left: 30.0, right: 30.0, top: 20.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
new Expanded(
child: new FlatButton(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
color: Colors.redAccent,
onPressed: () {
setState(() {
isLoading = true;
});
authHandler
.sendPasswordResetEmail(emailController.text)
.then((void nothing) {
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
content: new Text(
"Password reset email has been sent."),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
setState(() {
isLoading = false;
});
}).catchError((e) => print(e));
},
child: new Container(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
horizontal: 20.0,
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: Text(
"FORGOT PASSWORD",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
),
],
),
),
],
)));
}
}
Ideally, you'll want to call pop more than once. One for the modal, another for the actual route.
There are a few ways to achieve this. But ideally you'll want to await the close of the dialog before triggering another close:
foo() async {
await showDialog(
context: context,
builder: (context) => AlertDialog(
actions: [
new FlatButton(
child: new Text("OK"),
onPressed: () => Navigator.pop(context),
),
],
),
);
Navigator.pop(context);
}
This way, both the route and the modal can handle their close however they like.
This is how i did with mine
bool _logout = false;
and then at the start of build Widget
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
_onBackPressed(context);
return _logout;
},
child: Container(),
);
}
and the method _onBackPressed returns a custom dialog Class like so
void _onBackPressed(BuildContext c) async {
await showDialog(
barrierColor: CustomColors.darkGrey.withOpacity(0.8),
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
return CustomDialogBox(
title: 'Logout',
description: 'Are you sure you want to logout?',
rightButtonText: 'Yes',
onPClick: () {
_logout = true;
if (_logout == true) {
Get.back();
}
},
onNClick: () {
_logout = false;
Get.back();
},
);
});
if (_logout == true) {
Get.back();
}
}
and my custom Dialog class is here
class CustomDialogBox extends StatefulWidget {
final String? title, description, leftButtonText, rightButtonText;
final VoidCallback? onPClick, onNClick;
final Image? image;
const CustomDialogBox({
Key? key,
this.title,
this.description,
this.leftButtonText,
this.rightButtonText,
this.image,
this.onPClick,
this.onNClick,
}) : super(key: key);
#override
_CustomDialogBoxState createState() =>
// ignore: no_logic_in_create_state
_CustomDialogBoxState(onPClick!, onNClick!);
}
class _CustomDialogBoxState extends State<CustomDialogBox> {
final VoidCallback onPClick, onNClick;
_CustomDialogBoxState(this.onPClick, this.onNClick);
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(Dimensions.BORDER_RADIUS_4),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: Container(
//height: 200,
padding: const EdgeInsets.only(
left: 10,
right: 0,
bottom: 10,
),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: CustomColors.darkGrey,
offset: const Offset(0, 30),
blurRadius: 20,
),
]),
child: Wrap(children: <Widget>[
dialogBody(context),
]),
),
);
}
Widget dialogBody(context) {
return Column(children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Image.asset(
Images.LOGO,
height: MediaQuery.of(context).size.height * 0.035,
),
IconButton(
//padding: const EdgeInsets.all(0),
onPressed: () {
Get.back();
},
icon: const CircleAvatar(
radius: 12.5,
child: Icon(
Icons.close,
color: Colors.white,
),
backgroundColor: Colors.red,
),
),
]),
Padding(
padding: const EdgeInsets.only(
right: 10,
),
child: Column(children: [
//----//
customText(
text: widget.title ?? '',
fontFamily: 'black',
fontSize: 16,
),
//----//
const Space(0, 0.01),
//----//
customText(
text: widget.description ?? '',
fontSize: 14,
),
]),
),
//----//
const Space(0, 0.03),
//----//
Padding(
padding: const EdgeInsets.only(
right: 10,
),
child:
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
//----//
raisedButton(
text: widget.leftButtonText ?? 'Cancel',
fontFamily: 'roman',
height: 35,
width: 105,
buttonColor: CustomColors.red,
onClick: () {
return onNClick();
},
context: context,
),
//----//
raisedButton(
text: widget.rightButtonText ?? 'Okay',
fontFamily: 'roman',
height: 35,
width: 105,
buttonColor: CustomColors.green,
onClick: () {
return onPClick();
},
context: context,
),
//----//
]),
),
]);
}
}
the buttons and texts are custom so feel free to change them. and where you see Get.back(); is GetX code.. you can replace with Navigator.of(context).pop();
try this
showPop() async {
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
actions: [
new FlatButton(
child: new Text("Close"),
onPressed: () => Navigator.pop(context),
),
],
),
);
}