Related
Im a newbie, Not able to select items in Radio button, inside a ListTile. I tied to use same code without ListTile and working as expected. Looks like combination is not correct or i might be missing something.
class _TempState extends State<Temp> {
int selectedValue = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
child: Column(children: [
Row(
children: [
Expanded(
child: Text("Radio button with ListView",))],),
Expanded(
child: ListView.builder(
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
return OrderItem();
}),),
]))));}
Widget OrderItem() {
int selectedValue = 0;
return ListTile(
title: Container(
child: Column(children: [
Row(
children: [
Expanded(
child: Text(
"Product Type :",
)),
Radio<int>(
value: 1,
groupValue: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value != null ? value.toInt() : 1;
});
},
),
Text('NRML'),
Radio<int>(
value: 2,
groupValue: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value != null ? value.toInt() : 1;
});
}),
Text('MARKET'),
],), ])));
}}
You are updating your selectedValue in wrong way ,first define your selectedValue like this:
int? selectedValue;
then update your widget like this:
Widget OrderItem() {//remove int selectedValue = 0; here
return ListTile(
title: Container(
child: Column(
children: [
Row(
children: [
Expanded(
child: Text(
"Product Type :",
)),
Radio<int>(
value: 1,
groupValue: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value; //<-- change this
});
},
),
Text('NRML'),
Radio<int>(
value: 2,
groupValue: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value; //<-- change this
});
}),
Text('MARKET'),
],
),
],
),
),
);
}
Also another reason that is not working is that you are define another int selectedValue = 0; in your OrderItem method, you need to remove it.
In your second radio you should change your setState to
selectedValue = value != null ? value.toInt() : 2;
Value you assign to radio will be used to determine which radio is selected. So if you want to select second radio you should assign its value when selecting
selectedValue = value != null ? value.toInt() : 2;
Value you assign to radio will be used to determine which radio is selected. So if you want to select second radio you should assign its value when selecting
I just started learning flutter, I have programming knowledge before, but I am just getting used to the widget structure. What I want to do is add a button to the last element of the DropdownButton list and I used the DropdownMenuItem widget to do that. And I used Text as child and I put Button in the last element. The problem is, I can't give Text to the value property of the DropdownButton. That's why I'm getting an error because I've given a value that isn't in items [ ]. Is there any way I can get the value of the Text widget? Or can I do it another way? I hope I was explanatory.
code:
class _TodoPageState extends State<TodoPage> {
Text dropdownValue = Text('123'); // **FOR DEFAULT VALUE**
#override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.center,
children: [
MyTabBar(),
Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(left: 3, top: 5),
child: Row(
children: [
Ink(
width: 152,
height: 45,
padding: EdgeInsets.all(6),
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 2),
borderRadius: BorderRadius.circular(10),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: dropdownValue, **// CANT SET THE DEFAULT VALUE**
isExpanded: true,
icon: Image.asset('assets/down-list-arrow.png'),
iconSize: 10,
elevation: 16,
onChanged: (newValue) {
setState(() {
dropdownValue = newValue!; **// CANT SET THE DEFAULT VALUE**
});
},
items: [
DropdownMenuItem(child: Text('123'), value: ''),
DropdownMenuItem(child: Text('123'), value: ''),
DropdownMenuItem(
child: TextButton(
child: Text('Create'),
onPressed: () {},
))
],
),
),
)
],
),
),
),
],
),
MyListView()
],
),
));
}
}
I found 2 ways: Assigning create on values or check new value before assigning on onChanged and using FocusNode.
Test Widget
class TodoPage extends StatefulWidget {
TodoPage({Key? key}) : super(key: key);
#override
_TodoPageState createState() => _TodoPageState();
}
class _TodoPageState extends State<TodoPage> {
late String selectedValue; // **FOR DEFAULT VALUE**
late String selectedValue2;
List<String> dropDownItemValue = ['123', '2', '4', 'Create'];
List<String> dropDownItemValue2 = ['xx', '2', '4'];
late final dropDownKey2;
final FocusNode dropDownFocus = FocusNode();
#override
void initState() {
super.initState();
///selected value must be contain at dropDownItemValue
selectedValue = dropDownItemValue[0];
selectedValue2 = dropDownItemValue2[0];
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.deepPurple,
body: Center(
child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.center,
children: [
// MyTabBar(),
DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: selectedValue, // CANT SET THE DEFAULT VALUE**
isExpanded: true,
// icon: Image.asset('assets/down-list-arrow.png'),
iconSize: 10,
elevation: 16,
onChanged: (newValue) {
print(newValue);
setState(() {
selectedValue = newValue!; // SET THE DEFAULT VALUE**
});
},
/// dont assing same value on multiple widget
items: List.generate(
dropDownItemValue.length,
(index) => DropdownMenuItem(
child: Text('${dropDownItemValue[index]}'),
value: '${dropDownItemValue[index]}'),
),
),
),
SizedBox(
height: 100,
),
DropdownButtonHideUnderline(
child: DropdownButton<String>(
focusNode: dropDownFocus,
value: selectedValue2, // CANT SET THE DEFAULT VALUE**
isExpanded: true,
// icon: Image.asset('assets/down-list-arrow.png'),
iconSize: 10,
elevation: 16,
onChanged: (newValue) {
print(newValue == null);
// if value doesnt contain just close the dropDown
if (newValue == null) {
dropDownFocus.unfocus();
} else
setState(() {
selectedValue2 = newValue; // SET THE DEFAULT VALUE**
});
},
/// dont assing same value on multiple widget
items: List.generate(
dropDownItemValue2.length + 1,
(index) => index < dropDownItemValue2.length
? DropdownMenuItem(
child: Text('${dropDownItemValue2[index]}'),
value: '${dropDownItemValue2[index]}')
: DropdownMenuItem(
child: TextButton(
child: Text('Create'),
onPressed: () {},
),
),
),
),
),
],
),
),
));
}
}
am trying to save the formState in the elevated button below but, the validation goes through but when it starts saving I get this error : 'boolean expression must not be null', and I don't have any boolean to save.
I tried adding onSaved inside the dropDowns but still the same issue, anyone can help please?
class OfferPriceAndUsageWidget extends StatelessWidget {
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Consumer<AddOfferProvider>(
builder: (context, provider, snapshot) {
return Form(
key: _formKey,
child: Column(
children: [
CenteredSubtitleWidget(label: 'Prix et usage'),
LayoutBuilder(
builder: (context, constraints) {
final List<bool> searchType = [
provider.isBuy(),
!provider.isBuy(),
];
return ToggleButtons(
constraints: BoxConstraints.expand(
width: size.width / 2.1,
height: 50,
),
isSelected: searchType,
borderColor: Colors.teal.shade700,
borderWidth: 0,
borderRadius: BorderRadius.circular(10),
children: [
Text("Vente"),
Text("Location"),
],
onPressed: (index) {
switch (index) {
case 0:
provider.setBuy();
break;
case 1:
provider.setRent();
break;
default:
print('Error selecting the objectif.');
break;
}
},
);
},
),
verticalSpacer,
DropdownButtonFormField(
decoration: buildDropDownInputDecoration(hint: 'Usage'),
hint: Text("Usage"),
items: generateTerrainUsage(),
value: provider.offerInformation['usage'],
onChanged: (value) {
provider.setUsage(value);
},
),
verticalSpacer,
Row(
children: [
Expanded(
child: TextFormField(
initialValue: '20',
enabled: !provider.offerInformation['hidePrice'],
keyboardType: TextInputType.number,
onSaved: (value) {
if (provider.offerInformation['ispricePerMeter'])
provider.offerInformation['pricePerMeter'] = value;
provider.offerInformation['price'] = value;
},
validator: requiredElementValidator,
decoration: buildFormInputDecoration(
label: 'Prix (DT)',
),
),
),
horizontalSpacer,
Expanded(
child: TextFormField(
onSaved: (value) {
provider.offerInformation['surface'] = value;
},
validator: requiredElementValidator,
keyboardType: TextInputType.number,
decoration: buildFormInputDecoration(
label: 'Surface (m²)',
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Checkbox(
value: provider.offerInformation['hidePrice'],
onChanged: provider.toggleHidePrice,
),
GestureDetector(
onTap: () {
return provider.toggleHidePrice(
!provider.offerInformation['hidePrice'],
);
},
child: Text("Cacher le prix"),
),
if (!provider.offerInformation['hidePrice']) ...[
Checkbox(
value: provider.offerInformation['isPricePerMeter'],
onChanged: provider.togglePricePerMeter,
),
GestureDetector(
onTap: () {
return provider.togglePricePerMeter(
!provider.offerInformation['isPricePerMeter'],
);
},
child: Text("Prix par m²"),
),
]
],
),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () {
try {
if (_formKey.currentState.validate())
_formKey.currentState.save();
// print(provider.offerInformation);
} catch (e) {
print(e);
print(provider.offerInformation);
}
},
child: Text("Valider"),
),
)
],
),
],
),
);
},
);
}
}
About the currentState getter:
The current state is null if (1) there is no widget in the tree that matches this global key, (2) that widget is not a [StatefulWidget], or the associated [State] object is not a subtype of T.
Switch to a StatefulWidget and add a null check to currentState
_formKey.currentState!.validate()
_formKey.currentState!.save()
I am working on Radio Button in a ListView.builder() but when I select any of the radio button it is selecting each and every radio button rather than selected one.
My code is given below:
ListView.builder(
itemCount: 67,
itemBuilder: (BuildContext context, int index) {
return _buildCheckListItems(index);
}),
Widget _buildCheckListItems(int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'Seat Belts',
style: TextStyle(fontSize: 17),
),
Container(
width: 200,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Radio(
value: 1,
groupValue: selectedRadio,
activeColor: Colors.green,
onChanged: (val) {
changeValue(val);
},
),
Radio(
value: 2,
groupValue: selectedRadio,
activeColor: Colors.green,
onChanged: (val) {
changeValue(val);
},
)
],
),
),
],
);
}
changeValue(int val) {
setState(() {
selectedRadio = val;
});
}
The output result of above code is as follow:
Output result
The key point here is that you are using a same groupValue: selectedRadio, Each radio button group must have different groupValue otherwise it will shared the same change.
If you do not want to specify name for each radio button group you can just create a new .dart file:
import 'package:flutter/material.dart';
class buildCheckListItems extends StatefulWidget {
final int index;
buildCheckListItems(this.index); //I don't know what is this index for but I will put it in anyway
#override
_buildCheckListItemsState createState() => _buildCheckListItemsState();
}
class _buildCheckListItemsState extends State<buildCheckListItems> {
int selectedRadio = -1;
changeValue(int val) {
setState(() {
selectedRadio = val;
});
}
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
...
],
);
}
}
and now everything should be working just fine.
When i run the program on a device when i tick 2nd or 3rd term it does not take effect.
I am developing an Electronic student attendance tracking system so i decided to use a radio to track the term and also use check box to track the attendance that is checked if the student is present and unchecked if the student is not present but when i check the term radio it gives the correct output on the console but does not take effect on the physical screen.
import 'package:flutter/material.dart';
import 'package:atttendance_register/dataFiles/pupils.dart';
import 'package:atttendance_register/dataFiles/attendance.dart';
import 'package:intl/intl.dart';
class attendance extends StatefulWidget {
static Future<void> show(BuildContext context) async {
await Navigator.of(context).push(
MaterialPageRoute(builder: (context)=>attendance(),fullscreenDialog: true),
);
}
#override
_attendanceState createState() => _attendanceState();
}
class _attendanceState extends State<attendance> {
// final List<Pupils> pupils =[
// Pupils('John', ' Doe', 'Brad', 'Male', '001', DateTime.now(), '21'),
// Pupils('Jane', ' Doe', 'Mary', 'Female', '002', DateTime.now(), '21'),
// Pupils('Mohamed', ' James', '', 'Male', '003', DateTime.now(), '33'),
// Pupils('Titus', ' Nabieu', 'Jusu', 'Male', '004', DateTime.now(), '21'),
// Pupils('Steven', ' kai', 'Rogers', 'Male', '005', DateTime.now(), '21'),
// Pupils('Josephine', ' Bah', 'Neneh', 'Female', '006', DateTime.now(), '23')
//
// ];
final List<Attendance> attendance =[
Attendance(false,'John Doe Brad',DateTime.now(),0),
Attendance(true,'Jane Doe Mary',DateTime.now(),2),
Attendance(false,'Mohamed James',DateTime.now(),1),
Attendance(false,'Titus Nabieu Jusu',DateTime.now(),2),
Attendance(false,'Steven kai Rogers',DateTime.now(),2),
Attendance(false,'Josephine Bah Neneh',DateTime.now(),1)
];
bool selectedCheck = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Enter Attendance'),
backgroundColor: Colors.blue[900],
),
backgroundColor: Colors.blue[100],
body:Container(
child: ListView.builder(
itemCount:attendance.length,
itemBuilder:(BuildContext context, int index){
int selectedRadio = attendance[index].Term;
bool selectedCheck = attendance[index].attendance;
return Container(
child: Card(
child: Column(
//final pupil =pupils[index];
children: <Widget>[
Text(attendance[index].pupilName),
Text('Select Term'),
Row(
children: <Widget>[
Radio(
value:0,
groupValue: selectedRadio,
activeColor: Colors.blue,
onChanged: (T){
print(T);
setState(() {selectedRadio = T;}
);},
),
new Text(
'1st Term'
),
new Radio(
value: 1,
groupValue: selectedRadio,
activeColor: Colors.blue,
onChanged: (T){
print(T);
setState(() {selectedRadio = T;}
);
},
),
new Text(
'2nd Term'
),
new Radio(
value: 2,
groupValue: selectedRadio,
activeColor: Colors.blue,
onChanged: (T){
print(T);
setState(() {selectedRadio = T;}
);
},
),
new Text(
'3rd Term',
),
],
),
Row(
children: <Widget>[
Checkbox(
value: selectedCheck,
activeColor: Colors.blue,
onChanged: (bool value){
print(value);
setState(() {selectedCheck = value;}
);},
),
new Text(
'Present'
),
],
),
],
),
),
);
} ,),
),
);
}
// Widget pupilsCard(BuildContext context, int index){
// final pupil =pupils[index];
// bool selectedRadio = false;
//
// return Container(
// child: Card(
// child: Column(
// children: <Widget>[
// Text(pupil.FirstName+' '+pupil.OtherName+' '+pupil.LastName),
// Text('Select Term'),
// Row(
// children: <Widget>[
//
//
// ],
// ),
// Checkbox(
// value: selectedRadio,
// activeColor: Colors.blue,
// onChanged: (bool value){
// print(value);
// setState(() {selectedRadio = value;}
// );},
// ),
// new Text(
// 'Present'
//
// ),
// ],
// ),
// ),
// );
// }
}
In the onChanged property of your Radio widgets and your Checkbox widget, you are assigning the user selected value to the variable selectedRadio / selectedCheck and here is the problem, because when the new State is created through setState, the ListView is rebuilding and you are reassigning selectedRadio / selectedCheck the old value of the objects in this lines:
int selectedRadio = attendance[index].Term;
bool selectedCheck = attendance[index].attendance;
So you were not changing the actual value of the objects in the List, but you have too:
onChanged: (T) {
print(T);
setState(() => attendance[index].Term = T);
},
and
onChanged: (value) {
print(value);
setState(() => attendance[index].attendance = value);
},