Search code examples
flutterflutter-listview

Flutter: Creating pages new pages to show details from a ListView


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.


Solution

  • 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:

    enter image description here

    course detail:

    enter image description here

    For more info you can see pass data between screens