Situation:
I have a checkbox in one place and i am sending the callback etc. up the widget tree to run a setState and run the function applyFilters().
The NeededChecked is also routed up to the checkbox-value.
Question:
What i am struggling to understand is why this works.
Specifically how the onPressed callback is able to set the value of the bool isNeededState to true/false?
Here is the code that is run. The only important part is the passing of the bool isNeededState to the neededCheked.
void neededFilterCalled(bool isNeededState) {
setState(() {
NeededChecked = isNeededState;
applyFilters();
});
}
And here is the checkbox widget:
Widget build(BuildContext context) {
return Checkbox(
value: isNeededChecked,
onChanged: neededFilterCalled,
);
}
Writing
onChanged: neededFilterCalled,
is shorthand for
onChanged: (value) => neededFilterCalled(value),
onChanged provide nullable bool, defined as
required void Function(bool?)? onChanged
You can accept null value and provide false on null case like
void neededFilterCalled(bool? isNeededState) {
setState(() {
isNeededChecked = isNeededState ?? false;
applyFilters();
});
}
return Checkbox(
value: isNeededChecked,
onChanged: neededFilterCalled,
);
Related
I am trying to make essentially a Flutter multi-select input with an auto-complete search box, and I'm attempting to use the Material Autocomplete class with a custom User type to do so. The behavior I am after but having trouble with is for the text input to remain unchanged, even as the user makes selections.
What's making this a bit difficult is the displayStringForOption property. This property only takes the instance of the custom type corresponding to the user's selection, and as far as I can tell, nothing that indicates what the current text input is. This causes the input to be overwritten when the user makes a selection, which I would like to avoid. I don't believe the TextEditingController is available either.
Here's an example of what I have at the moment:
#override
Widget build(BuildContext context) =>
Autocomplete<User>(
fieldViewBuilder: _inviteeSearchInput,
displayStringForOption: (u) => '${u.name} - ${u.email}', // <== actually want this to just remain as the user's input
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return widget.availableUsers.where((user) => !_selectedUsers.contains(user));
}
return widget.availableUsers.where((User u) =>
!_selectedUsers.contains(u) && (u.name.toLowerCase().contains(textEditingValue.text.toLowerCase()) ||
u.email.toLowerCase().contains(textEditingValue.text.toLowerCase())));
},
optionsViewBuilder: ...,
onSelected: (u) {
setState(() {
_selectedUsers = { ..._selectedUsers, u };
});
},
);
Widget _inviteeSearchInput(
BuildContext context,
TextEditingController textEditingController,
FocusNode focusNode,
VoidCallback onFieldSubmitted,
) => TextFormField(
controller: textEditingController, // <== the TextEditingController is here, but I don't think that helps?
focusNode: focusNode,
decoration: ...
);
One thought I've tried that seems to work, but for some reason doesn't feel right is to keep track of the user input in a variable and update it with the onChanged property of the fieldViewBuilder:
class MultiSelectAutoCompleteState extends State<MultiSelectAutoComplete> {
Set<User> _selectedUsers = {};
String inputVal = ''; // <== var to keep track of user's input
// ...
#override
Widget build(BuildContext context) =>
Autocomplete<User>(
fieldViewBuilder: _inviteeSearchInput,
displayStringForOption: (u) => inputVal, // <== using that as the display string
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return widget.availableUsers.where((user) => !_selectedUsers.contains(user));
}
return widget.availableUsers.where((User u) =>
!_selectedUsers.contains(u) && (u.name.toLowerCase().contains(textEditingValue.text.toLowerCase()) ||
u.email.toLowerCase().contains(textEditingValue.text.toLowerCase())));
},
optionsViewBuilder: ...,
onSelected: (u) {
setState(() {
_selectedUsers = { ..._selectedUsers, u };
});
},
);
Widget _inviteeSearchInput(
BuildContext context,
TextEditingController textEditingController,
FocusNode focusNode,
VoidCallback onFieldSubmitted,
) => TextFormField(
controller: textEditingController,
onChanged: (s) => inputVal = s, // <== setting the var here
focusNode: focusNode,
decoration: ...
);
I'm not calling setState in the onChanged callback because I'm not sure I want to trigger a rebuild every time the input changes, but maybe I do?
I'm curious if there's a better way to do this, for some reason, this feels icky to me, and I'm also having a hard time reasoning about whether or not I want to call setState in the onChanged callback if I do go with the second option.
I doubt they developed radio button that's why my code is not working I checked flutter.dev but I didn't see something new ,Then I realized that the error is in the dart data types I use string where is the problem??
lass _MyAppState extends State<MyApp> {
String feel;
#override
Widget build(BuildContext context) {
return MaterialApp(
radio button code :
Text('good'),
Radio(
value: "good",
groupValue: feel,
onChanged: (val) {
setState(() {
feel = val;
print(feel);
});
})
can someone help me find what's wrong??
You need define feel as nullable because the onChange function of Radio return a nullable value , try this:
String? feel;
and also define Radio type like this:
Radio<String>(//<--- add this
value: "good",
groupValue: feel,
onChanged: (val) {
setState(() {
feel = val;
print(feel);
});
}),
How can I archive tristate for checkbox with nullsafety.... i have to pass null into that value but nullsafety has to perform null check on a variable, this is just contradicting .....
Putting null check as usual:
bool? parentvalue;
void update() {
parentvalue = null;
}
Checkbox(
....
value: parentvalue!,
onChanged: update(),
....
),
ERROR: Null check operator used on a null value
if I remove null check, code cannot compile at all
bool parentvalue;
void update() {
parentvalue = null;
}
Checkbox(
....
value: parentvalue,
onChanged: update(),
....
),
ERROR: A value of type 'Null' can't be assigned to a variable of type 'bool'.
=================================================================
UPDATE:
Checkbox(
tristate: true,
checkColor: Colors.white,
fillColor: MaterialStateProperty.resolveWith(getColor),
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
),
ERROR: Null check operator used on a null value
if i remove null check
onChanged: (bool value) {
setState(() {
isChecked = value;
});
},
ERROR: The argument type 'void Function(bool)' can't be assigned to the parameter type 'void Function(bool?)?'.
You need to add tristate: true in order to accept null. Also, the update() method needed to be changed because it provides nullable bool on callback.
Checkbox(
tristate: true,
value: parentvalue,
onChanged: update,
// onChanged:(value) { update(); },
),
And update method will be
void update(value) {
parentvalue = value;
setState(() {});
}
More about Checkbox on flutter.dev.
Here's an example with setting tristate to true:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Row(
children: [
MyCheckbox(),
],
),
),
);
}
}
class MyCheckbox extends StatefulWidget {
const MyCheckbox({Key? key}) : super(key: key);
#override
State<MyCheckbox> createState() => _MyCheckboxState();
}
class _MyCheckboxState extends State<MyCheckbox> {
bool? parentValue;
void update() {
setState(() {
parentValue = null;
});
}
#override
Widget build(BuildContext context) {
return Checkbox(
tristate: true,
value: parentValue,
onChanged: (_) {
update();
});
}
}
tristate property used for pass null value to checkbox as place of boolean
so if you want to pass null value to checkbox without showing any error then you have to set true value to the property of checkbox named tristate
like this
CheckBox(
....
tristate:true,
value:null,
...),
Let's discuss how Null safety works.
If you expecting a value(variable/object) that shouldn't be null then simply make that value null safety. In your case
bool? parentvalue .
& if you read Checkbox property
/// This property must not be null.
final bool? value;
/// If tristate is false (the default), [value] must not be null.
final bool tristate;
here value is null safety & you cannot assign null value on it.
so if you assign your parentvalue null this will be not accepted by, Checkbox value property. it only except Boolean(true/false).
void update() {
//Wrong
parentvalue = null;
}
So either you should make your parentvalue by default true or false as per requirements. or you can also use value: parentvalue??false/true to maintain null safety.
the value of Checkbox must be nut null
if you want to Checkbox be unChecked when value is null you can use this instead of null check
value: parentvalue??false
When I change the "Ulke" value from the AsyncSelectInputForm, I call the notifyListeners() method so that the "Il" value is null.
When I do this, the value I entered in the "Adres Başlığı" TextInputForm returns to its initial value.
My widget:
#override
Widget build(BuildContext context) {
var cariAdres = Provider.of<CariAdresProvider>(context);
return Column(
children: [
TextInputForm(
initialValue: cariAdres.cariAdres?.adresBasligi,
label: "Adres Başlığı",
onChanged: (value) {
cariAdres.cariAdresTemp =
cariAdres.cariAdresTemp?.copyWith(
adresBasligi: value,
);
},
),
//todo ulke select
AsyncSelectInputForm(
pageTitle: "Ülke Seç",
label: "Ülke",
initialLabel: cariAdres.cariAdresTemp?.ulkeIdStr,
labelSetter: (item) {
return item.ulkeStr;
},
onChanged: (value, item, context) {
cariAdres.cariAdresTemp =
cariAdres.cariAdresTemp?.copyWith(
ulkeId: value,
ulkeIdStr: item.ulkeStr,
ilId: null,
ilIdStr: null,
);
cariAdres.notifyListeners();
},
fetchPage: //...,
),
//todo il select
AsyncSelectInputForm(
initialValue: cariAdres.cariAdresTemp?.ilId,
//... same code
)
//....
It can be related a lot of possibilities, so we can't be sure which one is correct. But you can try to add some debugPrint in your build method in this way, you can expand your understanding for the situation.
Also, it can be about some logic in your change notifier provider or it can be about your widget tree-state or it can be about your sub widgets.
My problem was that I had set the initialValue of TextInputForm to value cariAdres.cariAdres?.adresBasligi and valued cariAdres.cariAdresTemp?.ulkeIdStr to AsyncSelectInputForm's initialLabel.
I was able to fix this problem by replacing the cariAdres.cariAdres?.adresBasligi value with the cariAdres.cariAdresTemp?.adresBasligi value. :)
Hi I am having an issue with radio and checkbox on flutter. I have created my own widget on the purpose of having different return widget depending on what is needed as on the picture bellow since I selected change pin the return will be a checkbox but the return widget is a checkbox while the save button is stagnant or didn't change but I am having an issue when i used radio or check box even Visibility. When I try to update the setState() it is not updating or reloading the widget. The code below is just the first return of the widget which will be a check box. When i try to unchecked the button the value becomes falls but the UI is not unchecked.
sample Image
Widget getInputType(val){
if(val == 'Pin Lock'){
return CheckboxListTile(
title: Text('Pin Login'),
value: isSwitchPin,
onChanged: (value){
setState(() {
print(value);
this.isSwitchPin = value;
});
});
}
}
You can try:
1, Define a field
ValueChanged<bool> onEnventChange;
2, On initState()
onEnventChange = (value){
setState(() {
print(value);
this.isSwitchPin = value;
});
});
3, Define your function
Widget getInputType(val){
if(val == 'Pin Lock'){
return CheckboxListTile(
title: Text('Pin Login'),
value: isSwitchPin,
onChanged: onEnventChange);
}
}