Values in RangeSlider inside AlertDialog not updating - flutter

I cannot understand why my rangeslider is not updating values when dragging. I am supposed to update the state with the onChanged function, but nothing seems to work. It only works when I press the "Apply" button and I reopen my alertDialog again, where I see the values of the slider updated. All this is wrapped inside and Appbar in a statefulWidget. When I press the filter button a pop up appears with the filter.
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Filter'),
content: SizedBox(
child: Card(
child: Column(
children: [
Text('Age'),
RangeSlider(
values: _rangeValues,
divisions: 20,
labels: RangeLabels(
_rangeValues.start.round().toString(),
_rangeValues.end.round().toString()),
onChanged: ( value ) {
_rangeValues = value ;
setState(() {
isFiltering = false;
varSelectedFilterAgeStart = value.start;
varSelectedFilterAgeEnd = value.end;
});
},
min: 0.0,
max: 20.0,
),
],
),
),
),
actions: [
ElevatedButton(
child: const Text('Apply'),
onPressed: () {
setState(() {
isFiltering = true;
varSelectedFilterAge = varSelectedFilterAgeStart;
});
Navigator.of(context).pop(varSelectedFilterAge);
},
),
ElevatedButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
What am I doing wrong??

Wrap your AlertDialog with StatefulBuilder and use its setState.
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) => AlertDialog(

Related

How to enable/disable dialog buttons (actions)

I have a helper function to create dialogs in my flutter app:
Future<void> showContentDialog(BuildContext context,
{required Widget content, String? title, List<Tuple2<String, void Function()>>? actions}) async {
Widget? titleWidget;
if (title != null) {
titleWidget = Text(
title,
style: Theme.of(context).textTheme.titleSmall!.copyWith(fontWeight: FontWeight.bold),
);
}
var dialogActions = <Widget>[];
if (actions != null) {
dialogActions.addAll(
actions.map(
(a) => TextButton(
child: Text(a.item1),
onPressed: () {
a.item2();
}),
),
);
}
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
title: titleWidget,
content: SizedBox(width: ThemeHelpers.maxPopupWidth, child: content),
actions: dialogActions,
),
);
}
There is another similar one that is used on Apple devices that uses equivalent widgets.
I can easyly manage state on the content portion of the dialog by wrapping it in a StatefulBuilder, but how can I enable and disable the dialog buttons (the actions passed to the AlertDialog) builder depending on content state?
My first idea was to add another a ValueNotifier parameter to the action builders and wrap them in ValueListenerBuilders but that didn't work.
Do I have any way of doing that other than including the actions as buttons inside the content (were I can easyly manage their state)?
You can pass null on onPressed to disable the button state. While it is not clear from where you like to controll the state, you can use ValueNotifier, and it work for all widget
final ValueNotifier<bool> enableButton = ValueNotifier(false);
Future<void> showContentDialog(
BuildContext context,
) async {
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
content: SizedBox(
width: 222,
child: Column(
children: [
Text("A"),
ElevatedButton(
onPressed: () {
enableButton.value = !enableButton.value;
},
child: Text("toggleButtonState"),
)
],
),
),
actions: [
ValueListenableBuilder<bool>(
valueListenable: enableButton,
builder: (context, value, child) => ElevatedButton(
onPressed: value ? () {} : null,
child: Text("BTN"),
),
),
],
),
);
}
In content add column and add dialog widgets in it
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
title: titleWidget,
content: Column(
mainAxisSize: MainAxisSize.min,
children : [
SizedBox(width: ThemeHelpers.maxPopupWidth, child: content),
dialogActions,
]
)
),
);

setstate for elevated button in dialog(Flutter)?

For the elevated button, I would like to show the visible/hide part content through setState. However, I could do it in normal pages but not a Dialog.
Here's the code:
bool addmaterial = true;
ClipRRect(
borderRadius: BorderRadius.circular(50),
child: SizedBox(
height: 40,
width: 400,
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(
Color(0xfff4f4f4)),
),
onPressed: () {
addmaterial = !addmaterial;
},
Try adding a StateFulBuilder inside your showDialog widget. If you want to change the state inside the showDialog
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
actions: <Widget>[],
content: Container(),
);
},
);
},
);

How to show pop up menu where icon button widget is clicked

I have made an alert dialog where user can update their profile details. In that with image container there is icon button widget. What I want is that when user clicks icon button, pop up menu will display with add/remove image option. Here is my code for alert dialog:
showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Edit detail'),
content: StatefulBuilder(
builder: (context, setState) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Stack(
alignment: Alignment.center,
children: [
Container(
//image container
),
GestureDetector(
// the pop up menu displays away from alert dialog
onTapDown: (TapDownDetails details) {
if (imageData != null) {
_showPopupMenu(details.globalPosition);
print('choose image/remove image');
} else {}
},
child: IconButton(icon: Icon(Icons.edit),
onPressed: () async {}),
)
]),
],
),
);
},
),
actions: <Widget>[
//action button
)],
);
},);
Here is the code for popup menu.
void _showPopupMenu(Offset offset) async {
double left = offset.dx;
double top = offset.dy;
await showMenu<String>(
context: context,
position: RelativeRect.fromLTRB(left, top, 0.0, 0.0), //position where want to show the menu on screen
items: [
PopupMenuItem<String>(
child: const Text('Add image'), value: '1'),
PopupMenuItem<String>(
child: const Text('Delete image'), value: '2'),
],
elevation: 8.0,
)
.then<void>((String itemSelected) {
if (itemSelected == null) return;
if(itemSelected == "1"){
} else {
}
});}
The menu displays outside the alert dialog. I have seen similar post with gesture detector but I can't seem to understand my mistake. Please help me and any improvements are welcome. Thanks in advance.
You can do it using the keys of AlertDialog and IconButton as the following
GlobalKey cKey = new GlobalKey();
GlobalKey pKey = new GlobalKey();
void _showPopupMenu() async {
await showMenu<String>(
context: context,
position: RelativeRect.fromRect(_getWidgetGlobalRect(pKey),_getWidgetGlobalRect(cKey)),
items: [
PopupMenuItem<String>(child: const Text('Add image'), value: '1'),
PopupMenuItem<String>(child: const Text('Delete image'), value: '2'),
],
elevation: 8.0,
).then<void>((String itemSelected) {
if (itemSelected == null) return;
if (itemSelected == "1") {
} else {}
});
}
Rect _getWidgetGlobalRect(GlobalKey key) {
RenderBox renderBox = key.currentContext.findRenderObject();
var offset = renderBox.localToGlobal(Offset.zero);
return Rect.fromLTWH(
offset.dx, offset.dy, renderBox.size.width, renderBox.size.height);
}
void showDialig() {
showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
key: cKey,
title: Text('Edit detail'),
content: StatefulBuilder(
builder: (context, setState) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Stack(alignment: Alignment.topRight, children: [
Container(
//image container
),
GestureDetector(
// the pop up menu displays away from alert dialog
onTapDown: (TapDownDetails details) {
_showPopupMenu();
},
child: IconButton(
key: pKey,
icon: Icon(Icons.edit),
onPressed: () async {}),
)
]),
],
),
);
},
),
actions: <Widget>[
//action button
],
);
},
);
}
If you'r using GestureDetector, there's a easy way i just did, Just put a GestureDetector inside another one, then set the onTap action if that's your case on both GestureDetector's, with the diference that in one you are gonna put an action, an in the other one you can just leave it empty, just like this.
GestureDetector(
onTap: () { //The Gesture you dont want to afect the rest
Navigator.pop(context);
},
child: Container(
color: Colors.transparent,
child:GestureDetector(
onTap: () {}, //This way is not going to afect the inside widget
child: Container() //your widget
)
)
)

How to change a button's text, based on input on text field

I have a small popup with a button "DELETE", however I want to change the text to "SELL" everytime the input text is different than 0.00
showDialog(
context: context,
builder: (context) {
String _popUpDeleteSoldText = "Delete";
return AlertDialog(
title: Text("Delete " + doc['propertyName'] + "?"),
content: Container(
height: 120,
child: Column(
children: <Widget>[
TextField(
onChanged: (text) {
if (text != "0.00") {
print("i'm != 0.00");
setState(() {
//TODO - THIS AIN'T WORKING
_popUpDeleteSoldText = "Sell";
});
} else {
print("i'm still 0");
setState(() {
_popUpDeleteSoldText = "Delete";
});
}
},
the button:
MaterialButton(
elevation: 4.0,
child: Text(
_popUpDeleteSoldText,
style: TextStyle(color: Colors.white),
)
....
The print are working on the onChange function, but the button text always say "Delete"
I would suggest to extract your AlertDialog into a separate StatefulWidget and then it will work.
You can wrap with StatefulBuilder directly like the following example
String contentText will change after use setState
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"),
),
],
);
},
);
},
);

flutter alert dialog for updating value

I want to update value in alert dialog i am using following:
Future showAlert() async {
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Alert in Dialog'),
content: Container(
height: 40.0,
width: 60.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_itemCount != 1
? new IconButton(
icon: new Icon(Icons.remove),
onPressed: () => setState(() => _itemCount--),
)
: new Container(),
new Text(_itemCount.toString()),
new IconButton(
icon: new Icon(Icons.add),
onPressed: () => setState(() => _itemCount++))
],
),
),
actions: <Widget>[
new FlatButton(
child: new Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
I am calling this function in Listview Builder
GestureDetector(
child: Align(
alignment: Alignment.topRight,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Icon(Icons.add_box,
color: Color(0xFFfccd01)),
),
),
onTap: () {
showAlert();
/* FutureBuilder<String>(
future: Add_to_cart(USER_ID,
snapshot.data[index].id, "1"),
builder: (context, snapshot) {
print(snapshot.data);
});*/
},
),
But on + click my value of alert dialog is not going to update after i close and reopen it it will update but i want to update on tap of icon button.
You can use StreamBuilder to update within Dialog or that screen also on single event thru Streams
You must insert AlertDialog into Statefulll Widget
see this example:
class ShowDialog extends StatefulWidget {
#override
_ShowDialogState createState() => _ShowDialogState();
}
class _ShowDialogState extends State<ShowDialog> {
#override
Widget build(BuildContext context) {
return AlertDialog(
//your container
);
}
}
and call ShowDialog into showDialog()