I have a clickable ListView and I want to have it open a new page to display detailed information when a card is clicked.
I have a ListView that builds itself automatically from a dictionary (not sure if that's the right term in flutter) that looks like this:
final courses = [
{
"name": "Course 1",
"date": "20/03/2024",
"logo": "course1",
"distance": 12967,
"temps" : 7384
},
{
"name": "Course 2",
"date": "06/03/2024",
"logo": "course2",
"distance" : 17413,
"temps" : 13854
},
{
"name": "Course 3",
"date": "27/02/2024",
"logo": "course3",
"distance" : 4967,
"temps" : 3891
},
];
There is currently only 3 entries for testing purpose but once finished it contain a variable number of entry.
The builder and the ListView look like this:
@override
Widget build(BuildContext context) {
return Center(
child: ListView.builder(
itemCount: courses.length,
itemBuilder: (context, index) {
final course = courses[index];
final logo = course['logo'];
final name = course['name'];
final date = course['date'];
return InkWell(
onTap: () => print('$name selected'),
child: Card(
child: ListTile(
leading: Image.asset("assets/images/$logo.png"),
title: Text('$name'),
subtitle: Text('course du $date'),
trailing: const Icon(Icons.more_vert),
),
),
);
},
),
);
}
}
What I want is to have the onTap open a new page displaying the information related to the selected dictionary entry. My guess is that I'd need to have onTap call a builder of some sort but I'm not sure how to go about doing that. I'm new to flutter and I'm not very familiar with builders and such.
You can pass data forward to screens using settings
parameter in MaterialPageRoute
when navigating to desired page:
Here's your Courses Screen, look how the course get passed:
class CoursesScreen extends StatelessWidget {
CoursesScreen({super.key});
List<Map<String,dynamic>> courses = [
{
"name": "Course 1",
"date": "20/03/2024",
"logo": "course1",
"distance": 12967,
"temps" : 7384
},
{
"name": "Course 2",
"date": "06/03/2024",
"logo": "course2",
"distance" : 17413,
"temps" : 13854
},
{
"name": "Course 3",
"date": "27/02/2024",
"logo": "course3",
"distance" : 4967,
"temps" : 3891
},
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child:
ListView.builder(
itemCount: courses.length,
itemBuilder: (context, index) {
final course = courses[index];
final logo = course['logo'];
final name = course['name'];
final date = course['date'];
return InkWell(
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>DetailsScreen(),
settings: RouteSettings(
arguments: course
)
),
),
child: Card(
child: ListTile(
leading: Text(logo),
title: Text(name),
subtitle: Text('course du $date'),
trailing: const Icon(Icons.more_vert),
),
),
);
},
)),
],
)
);
}
}
and Here's the Course Details Screen, Look how the passed data get received by that page:
class DetailsScreen extends StatelessWidget {
const DetailsScreen({super.key});
@override
Widget build(BuildContext context) {
var course = ModalRoute.of(context)!.settings.arguments as Map<String,dynamic>;
return Scaffold(
body: SafeArea(
child: Column(
children: [
Text('course name : ${course['name']}'),
Text('course date : ${course['date']}'),
Text('course logo : ${course['logo']}'),
],
),
),
);
}
}
You can pass data to screen also by taking data as a parameter in the Screen constructor, but it's not preferable.
courses:
course detail:
For more info you can see pass data between screens