I'm writing an alertDialog where the user can type a name.
The alertDialog has a "OK" button and a "Annulla" button. I want the "OK" button to be disabled while the textField is empty, and then enabled when the user types something.
I'm using a statefulBuilder as recommended by some answers here on StackOverflow, but clearly my implementation is not working.
// Function to display a dialog to insert a new item to the list
Future<void> _displayItemAddDialog(BuildContext context, provider) async {
String itemName;
// clear the textField and add the item to the list
Future<void> onOKPressed() {
_textFieldController.clear();
Navigator.pop(context);
provider.addItem(itemName);
}
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
// used to check if to enable the OK button
bool okButtonEnabled = false;
return AlertDialog(
title: Text('Inserisci Nome Oggetto'),
content: TextField(
onChanged: (value) {
itemName = value;
print(value);
// if the TextField is not empty then enable the button
if (value != "") {
// not working :(
setState() => okButtonEnabled = true;
}
},
controller: _textFieldController,
decoration: InputDecoration(hintText: 'Nome'),
),
actions: <Widget>[
TextButton(
onPressed: () {
_textFieldController.clear();
Navigator.pop(context);
},
child: Text('Annulla'),
),
TextButton(
// if button enabled then I change the assigned function
onPressed: okButtonEnabled ? onOKPressed : null,
child: Text('OK')),
],
);
});
});
}
You should move your okButtonEnabled outside StatefulBuilder, so right above it.
showDialog(
context: context,
builder: (context) {
// Move okButtonEnabled here
bool okButtonEnabled = false;
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text('Inserisci Nome Oggetto'),
content: TextField(
onChanged: (value) {
itemName = value;
print(value);
// if the TextField is not empty then enable the button
if (value != "") {
setState(() => okButtonEnabled = true);
}
},
controller: _textFieldController,
decoration: InputDecoration(hintText: 'Nome'),
),
actions: <Widget>[
TextButton(
onPressed: () {
_textFieldController.clear();
Navigator.pop(context);
},
child: Text('Annulla'),
),
TextButton(
// if button enabled then I change the assigned function
onPressed: okButtonEnabled ? onOKPressed : null,
child: Text('OK')),
],
);
},
);
},
);
Related
I using qr_code_scanner for scan a qr code & barcodes. Its scanning perfectly. But when i want to use dialog after scan for ask how much product did you scan and after that check it and control it.But when i use textfield inside of dialog and when i tap textfield camera stops working and its stays in black screen. What should i do ? What is wrong ? My codes for scan :
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) {
controller.pauseCamera();
player.play("scanner_sound.mp3");
inspect(args);
if (args.Barcode == scanData.code) {
showDialog(
context: context,
builder: (context) {
return WillPopScope(
onWillPop: () async {
Navigator.pop(context);
controller.resumeCamera();
return true;
},
child: AlertDialog(
title: const Text('Ürün Giriş'),
content: Column(
children: [
const Text('Bu üründen kaç adet okutuldu ?'),
TextField(
keyboardType: TextInputType.number,
controller: _controller,
),
],
),
actions: <Widget>[
TextButton(
onPressed: () {
bool isTrue = checkScannedCount(int.parse(_controller.text));
if (isTrue) {
var model = args.copyWith(ScannedCount: args.Count);
context.read<ProductCubit>().updateProduct(model);
Navigator.pop(context);
Navigator.pop(context);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Lütfen sayımı tekrarlayınız."),
),
);
Navigator.pop(context);
controller.resumeCamera(); //Its not starting camera again.
}
},
child: const Text('Tamam')),
],
),
);
});
} else {
showDialog(
context: context,
builder: (context) {
return WillPopScope(
onWillPop: () async {
Navigator.pop(context);
controller.resumeCamera();
return true;
},
child: AlertDialog(
title: const Text('Hatalı Barkod veya Ürün'),
content: const Text('Yanlış ürünü veya barkodu okutuyor olabilirsiniz. Kontrol edip tekrar ediniz.'),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context);
controller.resumeCamera();
},
child: const Text('Tamam')),
],
),
);
});
}
});
}
qr_code_scanner no longer supported . Since the underlying frameworks of this package, zxing for android and MTBBarcodescanner for iOS are both not longer maintaned . use mobile_scanner
When I tried to change the state from outside the function the state is not changing.
void _showAlertDialog(BuildContext context) {
// flutter defined function
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: const Text("Diabetes Prediction"),
content: StatefulBuilder(
return _predictedResult == "" ? Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
Text(loadingText),
],
) : Text(_predictedResult);
},
),
actions: <Widget>[
// usually buttons at the bottom of the dialog
TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Elevated button helps in calling the _showAlertDialog the loadingText is declared inside the class
ElevatedButton(
child: const Text("Predict"),
onPressed: () async {
// Pregnancies, Glucose, Blood Pressure, Insulin, Skin Thickness, Pedigree Function, Weight,
// Height, Age
_predictedResult = "";
loadingText = "";
var data = _formatData();
var result = Serializer().serialize(data);
_showAlertDialog(context);
setState(() {
loadingText = "Sending data to server...";
});
await Future.delayed(const Duration(seconds: 2), (){
});
setState(() {
loadingText = "Analyzing data...";
});
// await Future.delayed(const Duration(seconds: 2), (){
// print("data received");
// });
await _predict(result);
},
),
The output comes as Sending data to server...
String _predictedResult = '';
StreamController<String>? controller;
String loadingText = '';
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[900],
body: Center(
child: ElevatedButton(
child: const Text("Predict"),
onPressed: () async {
controller = StreamController<String>();
// Pregnancies, Glucose, Blood Pressure, Insulin, Skin Thickness, Pedigree Function, Weight,
// Height, Age
_predictedResult = "";
loadingText = "";
_showAlertDialog(context);
controller!.add("Sending data to server...");
await Future.delayed(const Duration(seconds: 2), () {});
controller!.add("Analyzing data...");
await Future.delayed(const Duration(seconds: 2), () {
print("data received");
});
controller!.add("data received!");
},
),
),
);
}
void _showAlertDialog(BuildContext context) {
// flutter defined function
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: const Text("Diabetes Prediction"),
content: StreamBuilder(
stream: controller!.stream,
builder: (context, AsyncSnapshot<String> snap) {
return _predictedResult == ""
? Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
Text(snap.data ?? "Loading..."),
],
)
: Text(_predictedResult);
},
),
actions: <Widget>[
// usually buttons at the bottom of the dialog
TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Use Stream
Flutter Stream Basics for Beginners
I have created one method outside the scaffold in the build method but not able to setState() from there.
I have written code like this :
#override
Widget build(BuildContext context) {
//Method that returns alert dialog
method(){
setState(() {
selectedType = newValue;
enableBrand = true;
});
}
//Main scaffold from where i'm calling the alert dialog method
return scaffold()
}
But this doesn't work, the state is not getting updated, so can anyone suggest what is the issue here?
I want to show an AlertDialog on click of a button so i have created a method for that in the build method and trying to setState() from there but it is not working.
Thanks in advance.
void _showDialog() {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder( // StatefulBuilder
builder: (context, setState) {
return AlertDialog(
actions: <Widget>[
],
);
},
);
},
);
}
First of all, is your class extending StatefulWidget?
In the onPressed of your button you could do something like this example.
An AlertDialog can give back a value when popped. I just took the example Alertdialog for now and returned a String.
Then you can set your state with the new value.
onPressed: () async {
var newValue = await showDialog(
context: context,
builder: (c) => AlertDialog(
title: Text('AlertDialog Title'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('This is a demo alert dialog.'),
Text(
'Would you like to approve of this message?'),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Approve'),
onPressed: () {
Navigator.of(context).pop("YOUR_NEW_VALUE");
},
),
],
));
//newValue now has the value "YOUR_NEW_VALUE"
setState((){
selectedType = newValue;
enableBrand = true;
});
}
i want to for loop a button i'm using this code but it show an error , i'm stuck here for 1 day thank you
I want to use for loop because this data is dynamic.
showDialog(
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return CupertinoAlertDialog(
title: Text('Add Location'),
actions: <Widget>[
for (var q = 1;q<=2;q++){
FlatButton(
child: new Text("Location A"),
onPressed: () {
Navigator.of(context).pop();
locationA = 'Location A';
},
),
}
],
);
},
);```
I have created a simple method that hopefully fits your needs. The method returns a list that uses a loop to add items to the list. In the end, it returns the populated list.
showDialog(
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return CupertinoAlertDialog(
title: Text('Add Location'),
actions: _getList(), // try with or without the ()'s
);
},
);
// the method
List<Widget> _getList() {
List<Widget> temp = [];
for (var q = 1; q<=2; q++) {
temp.add(
FlatButton(
child: new Text("Location A"),
onPressed: () {
Navigator.of(context).pop();
locationA = 'Location A';
},
);
);
}
return temp;
}
I have implemented a function to form submitting.I want to have SnackBar Alert to after submitted. I have tried but it doesn't work.After I added SnackBar routing also doesn't work.
addTicket() async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
try{
DocumentReference ref = await db.collection('CostalLineTicketDetails').
document(ticketCato).collection("Tickets").add(
{
'startStation':startStation,
'endStation':endStation,
'price':price,
'ticketType':ticketCato,
'contactNo':contactNo,
'dateTime':dateTime,
});
setState(() => id = ref.documentID);
Navigator.push(context, new MaterialPageRoute(builder: (context) => CostalLine()));
Scaffold.of(context).showSnackBar(SnackBar(content: Text('Ticket Added Sucessfully')));
}catch(e){
print(e);
}
}
}
}
You cannot show showSnackBar on same page after going to another screen.
You can declare _scaffoldKey and pass it to Scaffold like this
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Scaffold(
key: _scaffoldKey,
then open snackbar like this
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(
'Welcome',
),
duration: Duration(seconds: 2),
));
Output:
Edit
You can also use flash where you don't need to pass _scaffoldKey every time.
example:
void _showBasicsFlash({
Duration? duration,
flashStyle = FlashBehavior.floating,
}) {
showFlash(
context: context,
duration: duration,
builder: (context, controller) {
return Flash(
controller: controller,
behavior: flashStyle,
position: FlashPosition.bottom,
boxShadows: kElevationToShadow[4],
horizontalDismissDirection: HorizontalDismissDirection.horizontal,
child: FlashBar(
content: Text('This is a basic flash'),
),
);
},
);
}
try this,
addTicket() async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
try{
DocumentReference ref = await
db.collection('CostalLineTicketDetails').
document(ticketCato).collection("Tickets").add(
{
'startStation':startStation,
'endStation':endStation,
'price':price,
'ticketType':ticketCato,
'contactNo':contactNo,
'dateTime':dateTime,
});
setState(() => id = ref.documentID);
// Navigator.push(context, new MaterialPageRoute(builder: (context) => CostalLine()));
Scaffold.of(context).showSnackBar(SnackBar(content:
Text('Ticket Added Sucessfully')));
}catch(e){
print(e);
}
}
}
}
Define this code in any of the generalized dart file, and you can call this function at any place and will display a generic type scaffold.
import 'package:flutter/material.dart';
void showWarningSnackBar(BuildContext context, String message) {
// Find the Scaffold in the widget tree and use it to show a SnackBar.
ScaffoldFeatureController<Widget, dynamic> _scaffold;
// Find the Scaffold in the widget tree and use it to show a SnackBar.
_scaffold = Scaffold.of(context).showSnackBar(SnackBar(
content: InkWell(
onTap: () {
_scaffold.close();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
AppImage.asset(
assetName: YOUR_IMAGE_NAME,
fit: BoxFit.contain,
width: 20,
color: COLOR),
const SizedBox(
width: 10,
),
Text(
'$message',
maxLines: 2,
),
],
),
),
duration: const Duration(seconds: 10),
backgroundColor: COLOR,
));
}