Related
this is a typical question that might be considered as low quality but I have been on this for about two hours, and I am just trying to understand this piece of code better, so instead of just telling me how to fix, could you please also explain a bit what is happening. I am sure that for someone more experienced that me, should be very easy to spot.
I am trying to make a scrollable list, and draw each row of the list, and be able to click in each row item. But my app draws all the items but I am only able to see some of the items, as much as the screen allows, which means it is not scrollable.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Some App Page'),
),
body: ListView(
children: <Widget>[
Stack(
alignment: const Alignment(1.0, 1.0),
children: <Widget>[
TextField(
controller: cityController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(hintText: 'Enter city...'),
),
TextButton(
onPressed: () {
cityController.clear();
},
child: const Icon(Icons.clear),
),
],
),
ElevatedButton(
onPressed: () {
_futureTime = fetchTimes(int.parse(cityController.text));
if (cityController.text.isNotEmpty) {
setState(() {
cityController.clear(); // Clear value
}); // clear the textField
FocusScope.of(context)
.requestFocus(FocusNode()); // hide the keyboard
}
},
child: const Text('Get City', style: TextStyle(fontSize: 20)),
),
Column(
children: <Widget>[
Center(
child: FutureBuilder<Times>(
future: _futureTime,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return myTimeCard( date, index);
},
itemCount: data == null ? 0 : data.length,
);
},
),
),
],
),
],
),
);
}
Widget myTimeCard(String date, int index) {
return InkWell(
onTap: () {
// Navigate to the next page & pass data.
print("tapped, -> " + index.toString()); // for debugging purpose!
},
child: Stack(
children: <Widget>[
Opacity(
opacity: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Text(
index.toString(),
style: const TextStyle(
color: Colors.black,
fontSize: 22.0,
fontWeight: FontWeight.bold),
),
),
],
)
],
)
],
),
);
}
You are using two ListView s nested inside each other. In such cases you may need to let the Flutter know which ListView is the primary one. So, there is a property called primary. Try to set primary to false for the inner Listview.
return ListView.builder(
primary: false,
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return myTimeCard( date, index);
},
itemCount: data == null ? 0 : data.length,
);
The code you shared does not compile because I do not have additional context, so I had to spend some time to be able to make it compile, please make sure to provide a compilable code in the future.
the problem you're facing is because the main ListView is taking control of the scroll, to see the effect try scrolling by holding the screen from the button Get City.
There are many ways to solve this problem, depending on your goal, do you want to make the whole screen scrollable, or just the data list
Way 1. Make the whole screen scrollable:
by keeping the control of the scroll in the main ListView, and making all the descending widgets non-scrollable, which in your case, by making the widget that wraps the data a Column instead of ListView:
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final TextEditingController cityController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Some App Page'),
),
body: ListView(
children: <Widget>[
Stack(
alignment: const Alignment(1.0, 1.0),
children: <Widget>[
TextField(
controller: cityController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(hintText: 'Enter city...'),
),
TextButton(
onPressed: () {
cityController.clear();
},
child: const Icon(Icons.clear),
),
],
),
ElevatedButton(
onPressed: () {
_futureTime = fetchTimes(int.parse(cityController.text));
if (cityController.text.isNotEmpty) {
setState(() {
cityController.clear(); // Clear value
}); // clear the textField
FocusScope.of(context)
.requestFocus(FocusNode()); // hide the keyboard
}
},
child: const Text('Get City', style: TextStyle(fontSize: 20)),
),
Column(
children: <Widget>[
Center(
child: FutureBuilder<Times>(
future: _futureTime,
builder: (context, snapshot) {
// if (!snapshot.hasData) {
// return const CircularProgressIndicator();
// }
final data =
// snapshot.data;
List.generate(50, (index) => index.toString());
return Column(
children: [
for (int i = 0; i < data.length; i++)
myTimeCard(data[i], i)
],
);
},
),
),
],
),
],
),
);
}
Widget myTimeCard(String date, int index) {
return InkWell(
onTap: () {
// Navigate to the next page & pass data.
print("tapped, -> " + index.toString()); // for debugging purpose!
},
child: Stack(
children: <Widget>[
Opacity(
opacity: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Text(
index.toString(),
style: const TextStyle(
color: Colors.black,
fontSize: 22.0,
fontWeight: FontWeight.bold),
),
),
],
)
],
)
],
),
);
}
}
Way 2. make the non-data widgets non-scrollable, and keep the scroll control in the data widget:
can be done by converting the main ListView to a non-scrollable Widget (in your case Column), and wrapping the data list in Expanded widget, so it takes all the space it can have (for more info about Expanded):
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final TextEditingController cityController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Some App Page'),
),
body: Column(
children: <Widget>[
Stack(
alignment: const Alignment(1.0, 1.0),
children: <Widget>[
TextField(
controller: cityController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(hintText: 'Enter city...'),
),
TextButton(
onPressed: () {
cityController.clear();
},
child: const Icon(Icons.clear),
),
],
),
ElevatedButton(
onPressed: () {
_futureTime = fetchTimes(int.parse(cityController.text));
if (cityController.text.isNotEmpty) {
setState(() {
cityController.clear(); // Clear value
}); // clear the textField
FocusScope.of(context)
.requestFocus(FocusNode()); // hide the keyboard
}
},
child: const Text('Get City', style: TextStyle(fontSize: 20)),
),
FutureBuilder<Times>(
future: _futureTime,
builder: (context, snapshot) {
// if (!snapshot.hasData) {
// return const CircularProgressIndicator();
// }
final data =
// snapshot.data;
List.generate(50, (index) => index.toString());
return Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return myTimeCard(date, index);
},
itemCount: data == null ? 0 : data.length,
),
);
},
),
],
),
);
}
Widget myTimeCard(String date, int index) {
return InkWell(
onTap: () {
// Navigate to the next page & pass data.
print("tapped, -> " + index.toString()); // for debugging purpose!
},
child: Stack(
children: <Widget>[
Opacity(
opacity: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Text(
index.toString(),
style: const TextStyle(
color: Colors.black,
fontSize: 22.0,
fontWeight: FontWeight.bold),
),
),
],
)
],
)
],
),
);
}
}
The issue is coming because we have two scrollable ListView. While both of them are scrollable, while scrolling when the inner ListView it gets focused and parent become unfocus and scroll event only effect on inner ListView and you can't rollback to parent ListView, A simple solution will be using NeverScrollableScrollPhysics on inner
ListView.builder.
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
singleChildScrollView(
child: ListView.builder(
sinkwrap:true,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,)
)
Simple and Easy
I am trying to construct comment section in a project I am working on. And I want it the way facebook have done it. I have taken care of almost everything right now but how can I populate a field right below the original comment and create another comment field which will be typed when pressed reply?
Please have a look at the code and help me with this.
class MyHomePageState extends State<MyHomePage> {
Widget postComment(String time, String postComment, String profileName,
String profileImage, int likeCount) {
return Padding(
padding: EdgeInsets.only(left: 16.0, right: 16.0, top: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
CircleAvatar(maxRadius: 16, child: Image.asset(profileImage)),
SizedBox(
width: 16.0,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Hexcolor('#E9F1FE'),
borderRadius: BorderRadius.circular(6.0),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
profileName,
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
postComment,
style: TextStyle(fontSize: 16.0),
)
],
),
),
),
SizedBox(
height: 12.0,
),
Row(
children: [
Text(time, style: TextStyle(fontWeight: FontWeight.w600)),
SizedBox(
width: MediaQuery.of(context).size.width * 0.1,
),
Text('Like', style: TextStyle(fontWeight: FontWeight.w600)),
SizedBox(
width: MediaQuery.of(context).size.width * 0.1,
),
InkWell(
onTap: () {},
child: Text(
'Reply',
style: TextStyle(fontWeight: FontWeight.w600),
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.24,
),
InkWell(
onTap: () {
// _incrementCommentLikeCount();
},
child: Text('$likeCount')),
SizedBox(
width: MediaQuery.of(context).size.width * 0.02,
),
SvgPicture.asset('assets/like.svg')
],
)
],
)
],
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
///Just calling the widget for sake of example
postComment(
'2h', 'This is a comment', 'Unknown Name', 'assets/img1.png', 10)
],
));
}
}
Here is the output:
If you're looking for ways on how you can update a ListView, you can populate the ListView with a List of Objects i.e. List<Comment> _comments;.
As an example, you can create a Comment model
class Comment {
String commentId;
String userId;
String comment;
Timestamp timestamp;
Comment(
{required this.id,
required this.sender,
required this.comment,
required this.timestamp});
...
Then use the List to populate ListView.builder with data.
ListView.builder(
itemCount: _comments.length,
itemBuilder: (BuildContext context, int index) {
// Return a Widget for the comments
return Container(...);
}
)
You can then access Comment objects inside List<Comment> using the index provided by ListView.builder()
i.e. Text('${_comments[index].comment}')
To add new comments on the List, you can just add new Comment objects on the List.
_comments.add(Comment(
commentId: generatedCommentId,
userId: senderUserId,
comment: senderMessage,
timestamp: DateTime.now(),
));
I tried to build a list by taking the data I pulled from the database. But I do not see anything in any way, I get a white screen. I think the data I pulled is overlapping and preventing building lists but I couldn't find where the error is. What I'm trying to do is divide the Card by Row with 2 and write the data I pulled from the database on the left side of the Card. Write other data on the right.
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _db.getEventsByOrder(widget.index),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(child: Text("Loading.....")),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Container(
padding: const EdgeInsets.fromLTRB(8.0, 16.0, 8.0, 16.0),
child: Card(
elevation: 25,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Row(
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Text(
'${snapshot.data[index].title}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 28, fontFamily: 'Arvo'),
)),
Text(
"${snapshot.data[index].date} - ${snapshot.data[index].startTime == "null" ? " Tüm gün" : "${snapshot.data[index].startTime} - ${snapshot.data[index].finishTime}"}",
style: new TextStyle(
fontSize: 15, fontFamily: 'Arvo'),
),
Expanded(
child: Text(snapshot.data[index].desc,
maxLines: 2,
overflow: TextOverflow.ellipsis),
),
]),
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
child: DropDown(Event(
id: snapshot.data[index].id,
title: snapshot.data[index].title,
date: snapshot.data[index].date,
startTime:
snapshot.data[index].startTime,
finishTime:
snapshot.data[index].finishTime,
desc: snapshot.data[index].desc,
isActive:
snapshot.data[index].isActive,
choice:
snapshot.data[index].choice))),
Container(
padding: EdgeInsets.only(top: 8.0),
height: 100,
width: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: Colors.blue),
child: Text(
"${DateTime.parse(snapshot.data[index].date).difference(DateTime.now()).inDays}\nKalan Gün",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25),
),
),
],
),
],
),
),
),
);
});
}
}),
);
}
You need to adjust the dimensions only.
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _db.getEventsByOrder(widget.index),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(child: Text("Loading.....")),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Container(
padding: const EdgeInsets.fromLTRB(8.0, 16.0, 8.0, 16.0),
child: Card(
elevation: 25,
child: Container(
height: MediaQuery.of(context).size.height/4,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width / 2 - 16,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
'${snapshot.data[index].title}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 28),
),
Text(
"${snapshot.data[index].date} - ${snapshot.data[index].startTime == "null" ? " Tüm gün" : "${snapshot.data[index].startTime} - ${snapshot.data[index].finishTime}"}",
style: TextStyle(fontSize: 15),
),
Text(
snapshot.data[index].desc,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
),
Container(
width: MediaQuery.of(context).size.width / 2 - 32,
child: Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width / 4 - 8,
child: DropDown(Event(
id: snapshot.data[index].id,
title: snapshot.data[index].title,
date: snapshot.data[index].date,
startTime: snapshot.data[index].startTime,
finishTime: snapshot.data[index].finishTime,
desc: snapshot.data[index].desc,
isActive: snapshot.data[index].isActive,
choice: snapshot.data[index].choice)),
),
],
),
),
),
);
});
}
}),
);
}
If there was even an overlapping problem, should be an error. Provide the debug info and try to move DropDown out of container to column
You could also close ROW in a CONTAINER
I am working on a Flutter project that uses Firebase and has a StreamBuilder that creates a card that is similar to a blog App. Whenever I add a lot of "blogs", I get a bottom Overflow error and when I wrap body: MemoirsList(), in a SingleChildScrollView, the app won't let me scroll down.
Here is the code for the MemoirsList():
Widget MemoirsList() {
return Container(
child: memoirsStream != null
? ListView(
shrinkWrap: true,
children: <Widget>[
StreamBuilder(
stream: memoirsStream,
builder: (context, snapshot) {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
itemCount: snapshot.data.documents.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return MemoirsCard(
authorName: snapshot.data.documents[index].data['authorName'],
title: snapshot.data.documents[index].data["title"],
description: snapshot.data.documents[index].data['description'],
imgUrl: snapshot.data.documents[index].data['imgURL'],
);
});
},
)
],
)
: Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
}
Code for MemoirsCard():
class MemoirsCard extends StatelessWidget {
String imgUrl, title, description, authorName;
MemoirsCard({#required this.imgUrl, #required this.title, #required this.description, #required this.authorName});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 20),
height: 200,
child: Stack(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
imgUrl,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover
)
),
Container(
height: 200,
decoration: BoxDecoration(
color: Colors.black54.withOpacity(0.3),
borderRadius: BorderRadius.circular(10),
),
),
Container(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w700
),
),
SizedBox(height: 8),
Text(
description,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400
)
),
],
),
),
],
)
);
}
}
Listview.Builder inside Listview, it's not a good option which the flutter suggest you
Just replace top Listview with Column
Modify code like this
SingleChildScrollView(
child: Column(
children: <Widget>[
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
...
Here is the final code for anyone who is wondering:
Widget MemoirsList() {
return SingleChildScrollView(
child: memoirsStream != null
? Column(
children: <Widget>[
StreamBuilder(
stream: memoirsStream,
builder: (context, snapshot) {
if(snapshot.data == null) return CircularProgressIndicator(); //Removes called documents on null error
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
itemCount: snapshot.data.documents.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return MemoirsCard(
authorName: snapshot.data.documents[index].data['authorName'],
title: snapshot.data.documents[index].data["title"],
description: snapshot.data.documents[index].data['description'],
imgUrl: snapshot.data.documents[index].data['imgURL'],
);
});
},
)
],
)
: Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
}
Hi The problem is I have multiple groups of RadioButtons hence can't figure out how onChanged method will work for each group.
I have a list of students and want to make a widget where a teacher can mark attendance of students by clicking on one of the Radio Buttons( present,absent,holiday,half day etc.)
Here is the implementation
#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()}');
});
}
Here because there would be multiple students , hence there would be multiple groups of Radio Buttons so I have assigned each group a groupValue of id of the individual student. And because there are 4 radio buttons for each student (present,absent,holiday,halfday), I have assigned values of 0,1,2,3. And in onChanged method I am equating gp=value;
But it is not behaving the way I want it to behave.
//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(),
),
)
],
),
),
),
);
})
),
);
}