多个组未按预期工作的无线电中的 Flutter OnChanged 行为
Flutter OnChanged behaviour in Radios with multiple groups not working as expected
您好问题是我有多组 RadioButtons,因此无法弄清楚 onChanged 方法如何为每个组工作。
我有一个学生列表,想制作一个小部件,教师可以通过单击其中一个单选按钮(出席、缺席、假期、半天等)来标记学生的出勤情况。
这是实现
@override
Widget build(BuildContext context) {
print('number students ${studentList.students.length.toString}');
return ListView.builder(
itemCount: studentList.students.length,
itemBuilder: (context, index) {
var gp = studentList.students[index].id;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 10,
child: ListTile(
title: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
studentList.students[index].name,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
),
leading: CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(
studentList.students[index].details['photo'])),
trailing: Column(
children: <Widget>[],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Phone: ' +
studentList.students[index].details['phone']),
Text('Batches:'),
Container(
width: MediaQuery.of(context).size.width,
height: 50,
child: ListView.builder(
itemCount: studentList.students[index].batches.length,
itemBuilder: (context, batchIndex) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(studentList
.students[index].batches[batchIndex].name),
],
);
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Column(
children: <Widget>[
Radio(
groupValue: gp,
value: 0,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
),
Text('P')
],
),
Column(
children: <Widget>[
Radio(
groupValue: gp,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
value: 1,
),
Text('Ab')
],
),
Column(
children: <Widget>[
Radio(
groupValue: gp,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
value: 2,
),
Text('Hd')
],
),
Column(
children: <Widget>[
Radio(
groupValue: gp,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
value: 3,
),
Text('H')
],
)
],
),
)
],
),
),
),
);
});
}
updateSelectedAttendance(int gp, int e) {
setState(() {
gp = e;
print('gp ${gp.toString()} -- e ${e.toString()}');
});
}
这里因为会有多个学生,因此会有多组单选按钮,所以我为每个组分配了一个 groupValue of id of the individual student。因为每个学生有 4 个单选按钮(出席、缺席、假期、半天),所以我指定了 0、1、2、3 的值。在 onChanged 方法中,我等同于 gp=value;
但它的行为方式与我希望的不同。
//For the deom purpose I'm using Map List...
//Replace the above with your custom model
List<Map> studentList=[];
//Create attendance list to hold attendance
Map<String,String> attendance={};
List<String> labels=['P','Ab','Hd','H'];
@override
void initState() {
super.initState();
getData();
}
getData(){
//Use your own implementation to get students data
//For deom I'm using offline data
studentList.add({
'id':'ID1',
'name':'Naveen Avidi',
'details':'A Programmer'
//other fields...
});
attendance['ID1']='P';
//or null if emtpy
studentList.add({
'id':'ID2',
'name':'Ram',
'details':'An Engineer'
//other fields...
});
attendance['ID2']='Ab';
//or null if emtpy
studentList.add({
'id':'ID3',
'name':'Satish',
'details':'A Developer'
//other fields...
});
attendance['ID3']='Hd';
//or null if emtpy
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(
title:Text('Title')),
body: Container(
color:Colors.white,
child: ListView.builder(
itemCount: studentList.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
color:Colors.cyan,
elevation: 10,
child: ListTile(
title: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
studentList[index]['name'],
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold,color:Colors.black),
),
),
leading: CircleAvatar(
radius: 30,
//no pic available
),
trailing: Column(
children: <Widget>[],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Phone: ' +
studentList[index]['details'],
style:TextStyle(color:Colors.black)),
Text('Batches:',style:TextStyle(color:Colors.black)),
// Container(
// width: MediaQuery.of(context).size.width,
// height: 50,
// child: ListView.builder(
// itemCount: studentList.students[index].batches.length,
// itemBuilder: (context, batchIndex) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: <Widget>[
// Text(studentList
// .students[index].batches[batchIndex].name),
// ],
// );
// },
// ),
// ),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: labels.map((s){
return Column(
children: <Widget>[
Radio(
groupValue: attendance[studentList[index]['id']],
value: s,
onChanged: (newValue) {
setState((){
attendance[studentList[index]['id']]=newValue;
});
},
),
Text(s,style:TextStyle(color:Colors.black))
],
);
}).toList(),
),
)
],
),
),
),
);
})
),
);
}
您好问题是我有多组 RadioButtons,因此无法弄清楚 onChanged 方法如何为每个组工作。 我有一个学生列表,想制作一个小部件,教师可以通过单击其中一个单选按钮(出席、缺席、假期、半天等)来标记学生的出勤情况。 这是实现
@override
Widget build(BuildContext context) {
print('number students ${studentList.students.length.toString}');
return ListView.builder(
itemCount: studentList.students.length,
itemBuilder: (context, index) {
var gp = studentList.students[index].id;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 10,
child: ListTile(
title: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
studentList.students[index].name,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
),
leading: CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(
studentList.students[index].details['photo'])),
trailing: Column(
children: <Widget>[],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Phone: ' +
studentList.students[index].details['phone']),
Text('Batches:'),
Container(
width: MediaQuery.of(context).size.width,
height: 50,
child: ListView.builder(
itemCount: studentList.students[index].batches.length,
itemBuilder: (context, batchIndex) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(studentList
.students[index].batches[batchIndex].name),
],
);
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Column(
children: <Widget>[
Radio(
groupValue: gp,
value: 0,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
),
Text('P')
],
),
Column(
children: <Widget>[
Radio(
groupValue: gp,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
value: 1,
),
Text('Ab')
],
),
Column(
children: <Widget>[
Radio(
groupValue: gp,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
value: 2,
),
Text('Hd')
],
),
Column(
children: <Widget>[
Radio(
groupValue: gp,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
value: 3,
),
Text('H')
],
)
],
),
)
],
),
),
),
);
});
}
updateSelectedAttendance(int gp, int e) {
setState(() {
gp = e;
print('gp ${gp.toString()} -- e ${e.toString()}');
});
}
这里因为会有多个学生,因此会有多组单选按钮,所以我为每个组分配了一个 groupValue of id of the individual student。因为每个学生有 4 个单选按钮(出席、缺席、假期、半天),所以我指定了 0、1、2、3 的值。在 onChanged 方法中,我等同于 gp=value; 但它的行为方式与我希望的不同。
//For the deom purpose I'm using Map List...
//Replace the above with your custom model
List<Map> studentList=[];
//Create attendance list to hold attendance
Map<String,String> attendance={};
List<String> labels=['P','Ab','Hd','H'];
@override
void initState() {
super.initState();
getData();
}
getData(){
//Use your own implementation to get students data
//For deom I'm using offline data
studentList.add({
'id':'ID1',
'name':'Naveen Avidi',
'details':'A Programmer'
//other fields...
});
attendance['ID1']='P';
//or null if emtpy
studentList.add({
'id':'ID2',
'name':'Ram',
'details':'An Engineer'
//other fields...
});
attendance['ID2']='Ab';
//or null if emtpy
studentList.add({
'id':'ID3',
'name':'Satish',
'details':'A Developer'
//other fields...
});
attendance['ID3']='Hd';
//or null if emtpy
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(
title:Text('Title')),
body: Container(
color:Colors.white,
child: ListView.builder(
itemCount: studentList.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
color:Colors.cyan,
elevation: 10,
child: ListTile(
title: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
studentList[index]['name'],
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold,color:Colors.black),
),
),
leading: CircleAvatar(
radius: 30,
//no pic available
),
trailing: Column(
children: <Widget>[],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Phone: ' +
studentList[index]['details'],
style:TextStyle(color:Colors.black)),
Text('Batches:',style:TextStyle(color:Colors.black)),
// Container(
// width: MediaQuery.of(context).size.width,
// height: 50,
// child: ListView.builder(
// itemCount: studentList.students[index].batches.length,
// itemBuilder: (context, batchIndex) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: <Widget>[
// Text(studentList
// .students[index].batches[batchIndex].name),
// ],
// );
// },
// ),
// ),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: labels.map((s){
return Column(
children: <Widget>[
Radio(
groupValue: attendance[studentList[index]['id']],
value: s,
onChanged: (newValue) {
setState((){
attendance[studentList[index]['id']]=newValue;
});
},
),
Text(s,style:TextStyle(color:Colors.black))
],
);
}).toList(),
),
)
],
),
),
),
);
})
),
);
}