How to return data from Flutter dialog? - flutter

I'm having a dialog which opens up when click of a button and having a Listtile which Radio as a child in order to make a selection. As the user makes the selection and accepts it, I'm trying to update the selected part in the UI but i'm getting a null response while the value is being returned.
This is my custom statefull dialog
class _CustomScannerSelectDialogState extends State<CustomScannerSelectDialog> {
int selectedRadio;
setSelectedRadio(int val) {
setState(() {
selectedRadio = val;
});
}
#override
Widget build(BuildContext context) {
return Expanded(
child: Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: Stack(
children: [
Container(
padding: EdgeInsets.only(left: 20, top: 40, right: 20, bottom: 20),
margin: EdgeInsets.only(top: 40),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(color: Colors.black, offset: Offset(0, 10), blurRadius: 10),
]),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 20,
),
Text(
'Select the Scanner type',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
),
SizedBox(
height: 15,
),
ListTile(
title: const Text('QR & Barcode scanner'),
leading: Radio(
activeColor: Color(0xFFCC0000),
value: 1,
groupValue: selectedRadio,
onChanged: (val) {
print("Radio $val");
setSelectedRadio(val);
},
),
),
ListTile(
title: const Text('Barras Scanner'),
leading: Radio(
activeColor: Color(0xFFCC0000),
value: 2,
groupValue: selectedRadio,
onChanged: (val) {
print("Radio $val");
setSelectedRadio(val);
},
),
),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
CustomButton(
buttonText: 'CANCEL',
buttonFunction: () {
Navigator.pop(context);
return;
},
),
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), side: BorderSide(color: Colors.blueGrey)),
textColor: Color(0xFFCD853F),
color: Colors.white,
onPressed: () {
print("Selected radio is " + selectedRadio.toString());
Navigator.pop(context);
return selectedRadio.toString();
},
child: new Text(
'ACCEPT',
),
)
],
),
],
),
),
],
),
));
}
}
And on click of a button I'm calling a function as _showScannerSelectionDialog
_showScannerSelectionDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return CustomScannerSelectDialog();
},
).then((value) => print("Value is "+value.toString()));
}
Here the value I'm getting printed is null but i need the value of the selectedRadio

I think, you only need to simply use the following when closing the dialog:
var result = selectedRadio.toString(); // or any value.
Navigator.pop(context, result);

Related

Flutter || Checkbox on hover doesn't give on tap cursor permission

I am working on dropdownmenu items where in the drop-down menu item there are several checkboxes but any of the checkboxes on hover don't give on tap cursor permission.
This is a very strange thing I found out as I have already used the checkbox before but this type of error I didn't receive.
I think maybe the problem is in dropdownmenu.
I have also included the video for better understanding of my problem.
my code :-
Container(
width: 160,
//margin: const EdgeInsets.only(top: 10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), color: Colors.white),
child: ListTileTheme(
contentPadding: EdgeInsets.all(0),
dense: true,
horizontalTitleGap: 0.0,
minLeadingWidth: 0,
child: ExpansionTile(
iconColor: primaryBackgroundLightGrey,
title: Text(
listOFSelectedItem.isEmpty
? "Project type"
: listOFSelectedItem[0],
style: t5O40),
children: <Widget>[
Container(
height: 10,
color: primaryBackgroundLightGrey,
),
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.listOFStrings.length,
itemBuilder: (BuildContext context, int index) {
return Column(
children: [
Container(
height: 10,
),
Container(
margin: const EdgeInsets.only(bottom: 8.0),
child: _ViewItem(
item: widget.listOFStrings[index],
selected: (val) {
selectedText = val;
if (listOFSelectedItem.contains(val)) {
listOFSelectedItem.remove(val);
} else {
listOFSelectedItem.add(val);
}
widget.selectedList(listOFSelectedItem);
setState(() {});
},
itemSelected: listOFSelectedItem
.contains(widget.listOFStrings[index])),
),
],
);
},
),
],
),
),
),
class _ViewItem extends StatelessWidget {
String item;
bool itemSelected;
final Function(String) selected;
_ViewItem(
{required this.item, required this.itemSelected, required this.selected});
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Padding(
padding: EdgeInsets.only(
left: size.width * .015,
),
child: Row(
children: [
SizedBox(
height: 2,
width: 2,
child: Checkbox(
value: itemSelected,
onChanged: (val) {
selected(item);
},
hoverColor: Colors.transparent,
checkColor: Colors.white,
activeColor: Colors.grey),
),
SizedBox(
width: size.width * .010,
),
Text(item, style: t3O60),
],
),
);
}
}
You can adapt the example to your own code
dropdownBuilder: _customDropDownExample,
popupItemBuilder: _customPopupItemBuilderExample,
Widget _customDropDownExample(
BuildContext context, UserModel? item, String itemDesignation) {
if (item == null) {
return Container();
}
return Container(
child: (item.avatar == null)
? ListTile(
contentPadding: EdgeInsets.all(0),
leading: CircleAvatar(),
title: Text("No item selected"),
)
: ListTile(
contentPadding: EdgeInsets.all(0),
leading: CircleAvatar(
// this does not work - throws 404 error
// backgroundImage: NetworkImage(item.avatar ?? ''),
),
title: Text(item.name),
subtitle: Text(
item.createdAt.toString(),
),
),
);
After that
Widget _customPopupItemBuilderExample(
BuildContext context, UserModel item, bool isSelected) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 8),
decoration: !isSelected
? null
: BoxDecoration(
border: Border.all(color: Theme.of(context).primaryColor),
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
child: ListTile(
selected: isSelected,
title: Text(item.name),
subtitle: Text(item.createdAt.toString()),
leading: CircleAvatar(
// this does not work - throws 404 error
// backgroundImage: NetworkImage(item.avatar ?? ''),
),
),
);
I am using this package https://pub.dev/packages/dropdown_button2
Multiselect Dropdown with Checkboxes
final List<String> items = [
'Item1',
'Item2',
'Item3',
'Item4',
];
List<String> selectedItems = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Align(
alignment: AlignmentDirectional.center,
child: Text(
'Select Items',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
),
items: items.map((item) {
return DropdownMenuItem<String>(
value: item,
//disable default onTap to avoid closing menu when selecting an item
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
final _isSelected = selectedItems.contains(item);
return InkWell(
onTap: () {
_isSelected
? selectedItems.remove(item)
: selectedItems.add(item);
//This rebuilds the StatefulWidget to update the button's text
setState(() {});
//This rebuilds the dropdownMenu Widget to update the check mark
menuSetState(() {});
},
child: Container(
height: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
_isSelected
? const Icon(Icons.check_box_outlined)
: const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
],
),
),
);
},
),
);
}).toList(),
//Use last selected item as the current value so if we've limited menu height, it scroll to last item.
value: selectedItems.isEmpty ? null : selectedItems.last,
onChanged: (value) {},
buttonHeight: 40,
buttonWidth: 140,
itemHeight: 40,
itemPadding: EdgeInsets.zero,
selectedItemBuilder: (context) {
return items.map(
(item) {
return Container(
alignment: AlignmentDirectional.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
selectedItems.join(', '),
style: const TextStyle(
fontSize: 14,
overflow: TextOverflow.ellipsis,
),
maxLines: 1,
),
);
},
).toList();
},
),
),
),
);
}

How to automatically deactivate the previous button when clicking on another button?

I have 3 buttons. When you press the button, it turns purple. Only one button can be selected (activated). But now when one button is selected and I want to select another button, I need to first click on the same button (the previous one) and then click on the other button (the new one). How can I make it so that when you click on another button, it toggles, and the previous button is deactivated automatically?
Padding(
padding: const EdgeInsets.symmetric(horizontal: 21),
child: Row(
children: [
GestureDetector(
onTap: () => setState(() {
isVoltageAC = !isVoltageAC;
}),
child: _buttonVoltage('AC', isVoltageAC),
),
const SizedBox(width: 16),
GestureDetector(
onTap: () => setState(() {
isVoltageDC = !isVoltageDC;
}),
child: _buttonVoltage('DC', isVoltageDC),
),
const SizedBox(width: 16),
GestureDetector(
onTap: () => setState(() {
isVoltageAll = !isVoltageAll;
}),
child: _buttonVoltage('All', isVoltageAll),
),
],
),
),
Widget _buttonVoltage(String nameButton, bool isActive) => Container(
padding: const EdgeInsets.symmetric(vertical: 11),
height: 40,
width: 87,
decoration: BoxDecoration(
color: isActive
? constants.Colors.purpleMain
: constants.Colors.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isActive ? Colors.transparent : constants.Colors.greyDark,
),
boxShadow: [
BoxShadow(
color: isActive
? constants.Colors.purpleMain.withOpacity(0.34)
: Colors.transparent,
blurRadius: 10,
spreadRadius: 2,
offset: const Offset(0.0, 1.0)),
],
),
alignment: Alignment.center,
child:
Text(nameButton, style: constants.Styles.smallBoldTextStyleWhite),
);
I think it will be better to use enum here
enum VoltageMode {
ac,
dc,
all,
none, //not using
}
VoltageMode? selectedMode;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 21),
child: Row(
children: [
GestureDetector(
onTap: () => setState(() {
selectedMode = VoltageMode.ac;
}),
child: _buttonVoltage('AC', selectedMode == VoltageMode.ac),
),
const SizedBox(width: 16),
GestureDetector(
onTap: () => setState(() {
selectedMode = VoltageMode.dc;
}),
child: _buttonVoltage('DC', selectedMode == VoltageMode.dc),
),
const SizedBox(width: 16),
GestureDetector(
onTap: () => setState(() {
selectedMode = VoltageMode.all;
}),
child: _buttonVoltage('All', selectedMode == VoltageMode.all),
),
],
),
),
],
),
);
}
}
make int variable and call it selectedIndex and pass value when click on each button, for example when select 1 button set
GestureDetector(
onTap: () => setState(() {
isVoltageAC = !isVoltageAC;
selectedIndex = 1;
}),
child: _buttonVoltage('AC', isVoltageAC),
),
then pass this specific number to your _buttonVoltage widget and check it if it is equal to selectedIndex or not, if it is consider as active button, like this:
Widget _buttonVoltage(String nameButton, int index, int _selectedIndex) => Container(
padding: const EdgeInsets.symmetric(vertical: 11),
height: 40,
width: 87,
decoration: BoxDecoration(
color: _selectedIndex == index
? constants.Colors.purpleMain
: constants.Colors.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isActive ? Colors.transparent : constants.Colors.greyDark,
),
boxShadow: [
BoxShadow(
color: _selectedIndex == index
? constants.Colors.purpleMain.withOpacity(0.34)
: Colors.transparent,
blurRadius: 10,
spreadRadius: 2,
offset: const Offset(0.0, 1.0)),
],
),
alignment: Alignment.center,
child:
Text(nameButton, style: constants.Styles.smallBoldTextStyleWhite),
);

How to make Dependent DropdownButtonFormField in showDialog in flutter?

I make the Dependent DropdownButtonFormField in showDialog.
when i select the item of first dropdown the values not showing in second dropdown which is dependent on first dropdown.
But when i close the Dialog and reopen the dialog the values showing in second dropdown.
So here my Question is how to refresh second dropdown when first dropdown value is changed?
Future<bool> showDropDownDialog(title) async {
List<DropdownMenuItem<AllocationType>> items = [];
dropDownAllocationTypeModels.forEach((element) {
items.add(DropdownMenuItem(
child: Text(
element.allocationTypeName!,
style: Themes.getTextStyle(context),
),
value: element,
));
});
List<DropdownMenuItem<ServiceArea>> serviceAreaitems = [];
dropDownServiceAreaModels.forEach((element) {
serviceAreaitems.add(DropdownMenuItem(
child: Text(
element.serviceAreaName ?? "1",
style: Themes.getTextStyle(context),
),
value: element,
));
});
void onTeamChange(area) {
setState(() {
dropdownValueTeamType = null;
dropdownValueServiceArea = area;
dropDownTeamTypeModels = [];
});
ApiHelper()
.getTeamsByServiceArea(dropdownValueServiceArea!.id!)
.then((value) => {
setState(() {
dropDownTeamTypeModels = value;
})
});
}
return await showDialog(
context: context,
builder: (context) => Center(
child: Form(
key: _formKey,
child: Container(
padding: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Card(
color: Colors.blueGrey[100],
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15),
),
child: Container(
padding: EdgeInsets.all(10),
alignment: Alignment.center,
width: 300,
color:
Themes.getPrimaryDarkBackgroundColor(
context),
child: Text(
title,
style: Themes.getTitleTextStyleWhite(
context),
),
),
),
],
),
Padding(
padding: EdgeInsets.only(
left: Constants.APP_PADDING,
right: Constants.APP_PADDING,
top: Constants.APP_PADDING),
child: DropdownButtonFormField<ServiceArea>(
style: Themes.getTextFieldTextStyle(context),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: AppLocalizations.of(context)
.hintSelectServiceArea,
),
value: dropdownValueServiceArea,
isExpanded: true,
items: serviceAreaitems,
onChanged: (value) {
setState(() {
dropdownValueServiceArea = value;
onTeamChange(value);
});
},
),
),
Padding(
padding: EdgeInsets.only(
left: Constants.APP_PADDING,
right: Constants.APP_PADDING,
top: Constants.APP_PADDING),
child: DropdownButtonFormField<dynamic>(
style: Themes.getTextFieldTextStyle(context),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: AppLocalizations.of(context)
.hintSelectTeamType,
),
value: dropdownValueTeamType,
isExpanded: true,
items: dropDownTeamTypeModels.map((team) {
return DropdownMenuItem<dynamic>(
value: team,
child: Text(team),
);
}).toList(),
onChanged: (value) {
setState(() {
dropdownValueTeamType = value;
});
},
),
),
],
)),
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
),
],
),
),
),
),
) ??
false; //if showDialouge had returned null, then return false
}
As I see you use statefull widget approach.
So I believe you have to wrap parent dialog widget to statefull, declare variables (as dropdownValueServiceArea) in it, and change them inside dropdown callbacks with
setState(()=> dropdownValueServiceArea = newValue);

How to indent between DropdownButton and DropdownMenuItem in flutter

I am using DropdownButton and I am facing the following error. When opening the DropdownMenuItem list, I do not have an indent from the button itself. That is, I need to get the padding between the button (DropdownButton) and the dropdown list (DropdownMenuItem) so that there is a distance. But so far I haven't been able to do it. How can you make an indent between them?
code
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton2(
items: List.generate(
widget.items.length,
(index) => DropdownMenuItem<String>(
value: widget.items[index],
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: StatefulBuilder(
builder: (context, setStateSB) => GFCheckboxListTile(
value: _selectedTitles.contains(widget.items[index]),
onChanged: (bool selected) {
_onItemSelect(selected, index);
setStateSB(() {});
},
selected: selected,
title: Text(
widget.items[index],
style: constants.Styles.smallTextStyleWhite,
),
padding: const EdgeInsets.only(top: 12, bottom: 13),
margin: const EdgeInsets.only(right: 0, left: 0),
size: 22,
activeBgColor: constants.Colors.greyCheckbox,
activeBorderColor: constants.Colors.greyXMiddle,
inactiveBgColor: constants.Colors.greyCheckbox,
activeIcon: SvgPicture.asset(constants.Assets.checkboxIcon),
inactiveBorderColor: constants.Colors.greyXMiddle,
type: type,
),
),
),
),
),
hint: _selectedTitles.length > 1
? const Text('Selecte EV',
style: constants.Styles.bigBookTextStyleWhite)
: Text(_selectedTitles.join().toString(),
style: constants.Styles.bigBookTextStyleWhite),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 185,
dropdownWidth: 140,
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: constants.Colors.purpleMain,
),
color: constants.Colors.greyDark),
selectedItemBuilder: (context) {
return widget.items.map(
(item) {
return Row(
children: [
widget.icon ?? const SizedBox(),
const SizedBox(width: 8),
Text(
item,
style: constants.Styles.bigBookTextStyleWhite,
),
],
);
},
).toList();
},
),
),
);
}
}
In the dropdown_button2 documentation, there is a property for moving the dropdown menu Offset. You can see it here https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/DropdownButton2/offset.html
On that property you just need to set an Offset, which is composed of an X and Y values.
In your case it would look something like this:
DropdownButton2(
offset: Offset(0,10),
...
),

RadioListTile does not select correctly

I am Vaibhav Pathak. I have a a problem in using RadioListTile. I created two RadioListTile where on onChnaged property to call a function in which in call setState to set the value of selectedRadio variable to that value which I got from the function and It changed the variable value but does not reflect changes to the Ui means it does not select the pressed radio button.
My code is here :
showPaymentOptions() {
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25.0),
topRight: Radius.circular(25.0))),
elevation: 8.0,
context: context,
builder: (context) {
return Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
height: 240,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Column(
children: <Widget>[
Align(
alignment: Alignment.topLeft,
child: Text(
"Select Payment Method : ",
style: TextStyle(
color: Colors.black54,
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
),
SizedBox(
height: 7.0,
),
Card(
elevation: 8.0,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
RadioListTile(
activeColor: myTheme.primaryColor,
title: Text("COD"),
value: 1,
groupValue: selectedPaymentMethod,
onChanged: (value) =>
_changePayment(value)),
SizedBox(
height: 5.0,
),
RadioListTile(
activeColor: myTheme.primaryColor,
title: Text("Paytm"),
value: 2,
groupValue: selectedPaymentMethod,
onChanged: (value) =>
_changePayment(value)),
],
),
),
),
],
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"Pay ₹499",
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
isOrderSuccessful
? RaisedButton(
onPressed: () =>
placeOrder(selectedPaymentMethod),
color: myTheme.primaryColor,
textColor: Colors.white,
child: Text(
"Place Order",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0),
))
: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
myTheme.primaryColor))
],
),
],
),
)
],
)),
);
});
}
Code of setState function :
_changePayment(int value) {
print(value);
print(selectedPaymentMethod);
setState(() {
selectedPaymentMethod = value;
});
}
friends I have done it by myself. I used the StatefulBuilder widget and wrap the Column inside the column children I put my two ReadioListTile and in the onChanged property I put the _setStatewhich I got from the builder of StatefulBuilder and set the value of payment method variable to its value and then it works properly in which way I want it.
Answer Code :
StatefulBuilder(
builder: (context, _setState) {
return Column(
children: <Widget>[
RadioListTile(
activeColor: myTheme.primaryColor,
title: Text("Cash on Delivery"),
value: 1,
groupValue: selectedPaymentMethod,
onChanged: (value) => _setState(() {
selectedPaymentMethod = value;
})),
RadioListTile(
activeColor: myTheme.primaryColor,
title: Text("Paytm"),
value: 2,
groupValue: selectedPaymentMethod,
onChanged: (value) => _setState(() {
selectedPaymentMethod = value;
})),
],
);
},
),