How to show active mark on RadioListTile? - flutter

How to show active mark on RadioListTile? I used selected and activeColor but it does not work.
RadioListTile(
selected: true,
activeColor: Theme.of(context).primaryColor, //
title: Text(AppLocalizations.key(context, 'setDark')),
value: ThemeMode.dark,
groupValue: _themeMode,
onChanged: (value) {},
),

Documentation
"groupValue → T?
The currently selected value for this group of radio buttons.
This radio button is considered selected if its value matches the groupValue.
"
The one selected is the one whose group value matches the value.
Therefore your radio buttons should have as groupValue Theme.Dark or Theme.Light and update it on onChanged.

You need to create two RadioListTile for this and will contain the same groupValue. Based on groupValue it will decide active RadioListTile.
When value match with groupValue it will show active mark status.
class _HomesState extends State<Homes> {
ThemeMode _themeMode = ThemeMode.dark;
#override
Widget build(BuildContext context) {
return Scaffold(body: LayoutBuilder(
builder: (context, constraints) {
return Center(
child: Column(
children: [
RadioListTile<ThemeMode>(
selected: true,
activeColor: Theme.of(context).primaryColor,
title: Text(
'setDark',
),
value: ThemeMode.dark,
groupValue: _themeMode,
onChanged: (value) {
setState(() {
_themeMode = value!;
});
},
),
RadioListTile<ThemeMode>(
selected: true,
activeColor: Theme.of(context).primaryColor,
title: Text(
'setLight',
),
value: ThemeMode.light,
groupValue: _themeMode,
onChanged: (value) {
setState(() {
_themeMode = value!;
});
},
),
],
),
);
},
));
}
}

Related

SetState() does not change my state in a PopupMenuButton

My screen bears a popup menu where the user can pass in expert mode by taping on a button (see the screen shot below).
But, though the setState() is being executed, the redraw always resets ìsExpertMode' to its default value (true).
class _SmartboxDashboard extends State<SmartboxDashboard>
with
Module<SmartboxDashboard>,
SingleTickerProviderStateMixin,
AutomaticKeepAliveClientMixin<SmartboxDashboard> {
/// Is expert mode?
bool isExpertMode = true;
return DefaultTabController(
length: _tabSectionBodies.length,
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
bottom: TabBar(isScrollable: true, tabs: tabSectionTabs),
title: Text(deviceDisplayName(widget.device.name)),
actions: [
PopupMenuButton(
icon: Icon(Icons.menu),
position: PopupMenuPosition.under,
itemBuilder: (context) {
return [
PopupMenuItem<int>(
value: 2,
child: ListTile(
leading: ElevatedButton(
child: Text(isExpertMode
? "Normal mode"
: "Expert mode"),
//value: isExpertMode,
onPressed: () {
setState(() {
isExpertMode =
appState.isExpertMode = !isExpertMode;
});
}),
title: Text(
isExpertMode ? "Expert mode" : "Normal mode"),
subtitle: Text(isExpertMode
? "Turning to \"normal mode\" will streamline the information and you only see essentials informationabout your battery"
: "Turning to \"expert mode\" will show more screens and deeper information about your batteries"),
)
),
];
},
onSelected: (value) async {
switch (value) {
case 2:
//setState(() {
// isExpertMode = appState.isExpertMode = !isExpertMode;
// print("Expert mode turned to $isExpertMode");
});
break;
}
setState(() {
sharing = false;
});
}),
]),
body: TabBarView(children: _tabSectionBodies),
you can use StatefulBuilder
bool isSwitched = true;
PopupMenuItem(child: StatefulBuilder(
builder: (BuildContext context,
void Function(void Function()) setState) {
return Switch(
value: isSwitched,
onChanged: (value) {
setState(() {
isSwitched = value;
print(isSwitched);
});
},
activeTrackColor: Colors.lightGreenAccent,
activeColor: Colors.green,
);
},
))
I think it should be
isExpertMode = !isExpertMode;.
You need to use StatefulBuilder here, because the context and setState scope has been changed. Whenever new StatefulBuilder Widget is used you will get a new setState local function to update the state.

How to select a default radio button in flutter

I have implemented three radio buttons in my flutter project. But after executing the application, none of the radio buttons are showing selected. Can anyone help me where I am getting wrong please !
There is no radio button is getting selected although I click on it. I am unable to figure out the reason. Please help me solving it. Here is my code :
class AdminHomeContent extends StatefulWidget {
#override
_AdminHomeContentState createState() => _AdminHomeContentState();
}
class _AdminHomeContentState extends State<AdminHomeContent> {
static final Map<String, Color> options = {
'All': Colors.black, 'Cancelled':Colors.red,
'Pending': Colors.yellow, 'Visited': Colors.green[900],
};
List keyList = options.keys.toList();
List keyColor = options.values.toList();
String selectedOption = 'All';
int groupValue = 0 ;
void buttonValue(int v){
setState(() {
groupValue = v ;
});
}
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<PatientDataNotifier>(
create: (context) => PatientDataNotifier(),
child: MaterialApp(
home: Scaffold(
// some of my other codes
----------
-----------
//method that defines three radio buttons
Future<dynamic> getStatus(BuildContext context) {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: SingleChildScrollView(
child: Container(
child: Column(
children: [
Row(
children: [
Radio(value: 1,
activeColor: Colors.blue,
groupValue: groupValue,
onChanged: (int v){
print(v);
buttonValue(v);
}
),
Text(keyList[2] , style: TextStyle(color: keyColor[2]),)
],
),
Row(
children: [
Radio(value: 2,
activeColor: Colors.blue,
groupValue: groupValue,
onChanged: (int v) {
print(v);
buttonValue(v);
}
),
Text(keyList[3] , style: TextStyle(color: keyColor[3]))
],
),
Row(
children: [
Radio(value: 3,
activeColor: Colors.blue,
groupValue: groupValue,
onChanged: (int v) {
print(v);
buttonValue(v);
}
),
Text(keyList[1] , style: TextStyle(color: keyColor[1]))
],
)
],
),
),
),
);
}
);
}
// some codes
------------------
-----------------
//calling the getStatus() inside the onTap() property of a Text
GestureDetector(
child: Text(patient.status,
style: getTextStyle('Poppins-Regular',15.0, FontWeight.bold, options[status]),
),
onTap: () async{
await getStatus(context);
},
),
}
}
None of the radio buttons are getting selected even after clicking on it. Please help me solving it.
First of all, none of Radio is selected by default because your initial groupValue is 0 and none of your Radio has this value.
Here a fully example of working Radio
class MyRadio extends StatefulWidget {
#override
_MyRadioState createState() => _MyRadioState();
}
int groupValue = 1;
class _MyRadioState extends State<MyRadio> {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Column(
children: [
Radio(
value: 1,
activeColor: Colors.blue,
groupValue: groupValue,
onChanged: (int v) {
buttonValue(v);
},
),
Radio(
value: 2,
activeColor: Colors.blue,
groupValue: groupValue,
onChanged: (int v) {
buttonValue(v);
},
),
Radio(
value: 3,
activeColor: Colors.blue,
groupValue: groupValue,
onChanged: (int v) {
buttonValue(v);
},
),
],
),
),
),
);
}
void buttonValue(int v) {
setState(() {
groupValue = v;
});
}
}

Uncheck a checkbox when user checking another one (bool of checkbox is in a map)

I have in my app a few checkboxes and I want, when the user checks a checkbox, that the other checkboxes are unchecked. That's normally not difficult at all, but the problem is that I have the bool and the title of the checkbox in a map. How can I uncheck all checkboxes except the one the user checkt?
This is the map:
Map<String, bool> filterOptions = {
'Test1': false,
'Test2': false,
};
This is the code where I "build" the checkboxes:
ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: filterOptions.keys.map((String key) {
return CheckboxListTile(
title: Text(key),
value: filterOptions[key],
onChanged: (bool value) {
setState(() {
filterOptions[key] = value;
});
},
);
}).toList(),
),
What you are looking for is not a checkbox, but a Radio Button. You can only select one radio button at a time and you don't have to manually check the state. However, if you insist on the checkboxes you can iterate through the map
filterOptions.forEach((key, value) => filterOptions[key] = false);
If you set value to false, you will just change the copy of the value. You might consider dropping the map and go for a single int selectedBox variable.
The purpose of a checkbox is for multiple user group selection.
In other words, if you want to unselect when a user selects another option then
RadioButton
would be the best option.
SingingCharacter _character = SingingCharacter.lafayette;
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ListTile(
title: const Text('Male'),
leading: Radio(
value: SingingCharacter.lafayette,
groupValue: _character,
onChanged: (SingingCharacter value) {
setState(() {
_character = value;
});
},
),
),
ListTile(
title: const Text('Female'),
leading: Radio(
value: SingingCharacter.jefferson,
groupValue: _character,
onChanged: (SingingCharacter value) {
setState(() {
_character = value;
});
},
),
),
],
);
}
Screenshot
Source: Flutter RadioButton

onPressed create multiple instances of CheckboxListTile in Flutter

I'm new to flutter so I'm not sure how to go about this. I want to be able to add another instance of the same CheckboxListTile when a user presses a button right below the most recent CheckboxListTile.
The code for how it currently is is below.
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
CheckboxListTile(
title: TextField(
autocorrect: true,
),
value: checkBoxValue,
secondary: Icon(Icons.assignment),
onChanged: (bool newValue) {
setState(() {
checkBoxValue = newValue;
});
}
),
],
The code of an example of how I would want the app to appear after a user presses is below.
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
CheckboxListTile(
title: TextField(
autocorrect: true,
),
value: checkBoxValue,
secondary: Icon(Icons.assignment),
onChanged: (bool newValue) {
setState(() {
checkBoxValue = newValue;
});
}
),
CheckboxListTile(
title: TextField(
autocorrect: true,
),
value: checkBoxValue,
secondary: Icon(Icons.assignment),
onChanged: (bool newValue) {
setState(() {
checkBoxValue = newValue;
});
}
),
],
Thanks in advance!
Generating widgets in a ListView is by adding List<Widget> in its children. Simply put, it roughly looks similar to.
ListView(
children: <Widget>[widgetA, widgetA, widgetC]);
What you need to do is to manually add widgets in List<Widget>. You can create a List<Widget> _checkboxList and create a function that returns a CheckboxListTile widget.
CheckboxListTile _checkboxListTile(){
return CheckboxListTile(
title: TextField(
autocorrect: true,
),
value: checkBoxValue,
secondary: Icon(Icons.assignment),
onChanged: (bool newValue) {
setState(() {
checkBoxValue = newValue;
});
}
);
}
and on your button, call _checkboxList.add(_checkboxListTile()); to add it on List<Widget> _checkboxList
RaisedButton(
onPressed: () {
setState(() {
_checkboxList.add(_checkboxListTile());
});
},
child: Text('Add checkbox'),
),
To display List _checkboxList on your screen:
Widget build(BuildContext context) {
return ListView(children: _checkboxList);
}
Let me know if this helps.
One way you could do it is by using a ListView.builder like this..
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<bool> checkBoxesCheckedStates = [false];
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: checkBoxesCheckedStates.length,
itemBuilder: (BuildContext context, int index){
return CheckboxListTile(
title: TextField(
autocorrect: true,
),
value: checkBoxesCheckedStates[index],
secondary: Icon(Icons.assignment),
onChanged: (bool newValue) {
setState(() {
checkBoxesCheckedStates[index] = newValue;
});
},
);
},
),
),
RaisedButton(
child: Text('Add'),
onPressed: (){
setState(() {
checkBoxesCheckedStates.add(false);
});
},
),
],
);
}
}

Checkbox form validation

How can I validate a checkbox in a Flutter Form? Every other validation works fine, but the checkbox doesn't show an Error.
Here is my code:
FormField(
validator: (value) {
if (value == false) {
return 'Required.';
}
},
builder: (FormFieldState<dynamic> field) {
return CheckboxListTile(
value: checkboxValue,
onChanged: (val) {
if (checkboxValue == false) {
setState(() {
checkboxValue = true;
});
} else if (checkboxValue == true) {
setState(() {
checkboxValue = false;
});
}
},
title: new Text(
'I agree.',
style: TextStyle(fontSize: 14.0),
),
controlAffinity: ListTileControlAffinity.leading,
activeColor: Colors.green,
);
},
),
A cleaner solution to this problem is to make a class that extends FormField<bool>
Here is how I accomplished this:
class CheckboxFormField extends FormField<bool> {
CheckboxFormField(
{Widget title,
FormFieldSetter<bool> onSaved,
FormFieldValidator<bool> validator,
bool initialValue = false,
bool autovalidate = false})
: super(
onSaved: onSaved,
validator: validator,
initialValue: initialValue,
builder: (FormFieldState<bool> state) {
return CheckboxListTile(
dense: state.hasError,
title: title,
value: state.value,
onChanged: state.didChange,
subtitle: state.hasError
? Builder(
builder: (BuildContext context) => Text(
state.errorText,
style: TextStyle(color: Theme.of(context).errorColor),
),
)
: null,
controlAffinity: ListTileControlAffinity.leading,
);
});
}
in case if you want to put your checkbox directly in your Form widget tree you can use solution provided below with FormField widget. Instead of using ListTile I used rows and columns as my form was requiring different layout.
FormField<bool>(
builder: (state) {
return Column(
children: <Widget>[
Row(
children: <Widget>[
Checkbox(
value: checkboxValue,
onChanged: (value) {
setState(() {
//save checkbox value to variable that store terms and notify form that state changed
checkboxValue = value;
state.didChange(value);
});
}),
Text('I accept terms'),
],
),
//display error in matching theme
Text(
state.errorText ?? '',
style: TextStyle(
color: Theme.of(context).errorColor,
),
)
],
);
},
//output from validation will be displayed in state.errorText (above)
validator: (value) {
if (!checkboxValue) {
return 'You need to accept terms';
} else {
return null;
}
},
),
You could try something like this :
CheckboxListTile(
value: checkboxValue,
onChanged: (val) {
setState(() => checkboxValue = val
},
subtitle: !checkboxValue
? Text(
'Required.',
style: TextStyle(color: Colors.red),
)
: null,
title: new Text(
'I agree.',
style: TextStyle(fontSize: 14.0),
),
controlAffinity: ListTileControlAffinity.leading,
activeColor: Colors.green,
);
The above answer is correct, however, if you want to display an error message that is more consistent with the default layout of a TextFormField widget error message, then wrap the Text widget in a Padding widget, and give it the hex colour #e53935.
Note: You may need to adjust the left padding to fit the CheckboxListTile widget is also wrapped in a Padding widget.
Check the code below:
bool _termsChecked = false;
CheckboxListTile(
activeColor: Theme.of(context).accentColor,
title: Text('I agree to'),
value: _termsChecked,
onChanged: (bool value) => setState(() => _termsChecked = value),
subtitle: !_termsChecked
? Padding(
padding: EdgeInsets.fromLTRB(12.0, 0, 0, 0),
child: Text('Required field', style: TextStyle(color: Color(0xFFe53935), fontSize: 12),),)
: null,
),