List Applications are everywhere. Social Media Apps, Note Taking Apps. Yes, the list won’t end.
So if you are trying to make a List App and want to navigate to a new screen when the user taps.
This post will definitely good for you.
Contents
1. ListView Navigation: Navigate To New Screen.
In this simple example, you will learn how to navigate to a different screen through ListTile onTap function.
- I have used 3 ListTiles. When the user taps a ListTile, it calls onTap Function.
- Then Navigator pushes the screen.
Below is the code.
ListTile( title: Text('First Screen'), trailing: Icon(Icons.keyboard_arrow_right_sharp), //onTap calls When ListTile Taps onTap: () { //Navigator pushes FirstScreen. Navigator.push( context, MaterialPageRoute( builder: (context) => FirstScreen(), ), ); }, ),
Full source code is given below.
import 'package:flutter/material.dart'; import 'first_screen.dart'; import 'second_screen.dart'; import 'third_screen.dart'; void main() { runApp( MyApp(), ); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter ListView Navigation I', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyListView(), ); } } class MyListView extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter ListView Navigation I'), ), body: ListView( children: [ ListTile( title: Text('First Screen'), trailing: Icon(Icons.keyboard_arrow_right_sharp), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => FirstScreen(), ), ); }, ), ListTile( title: Text('Second Screen'), trailing: Icon(Icons.keyboard_arrow_right_sharp), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => SecondScreen(), ), ); }, ), ListTile( title: Text('Third Screen'), trailing: Icon(Icons.keyboard_arrow_right_sharp), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ThirdScreen(), ), ); }, ), ], ), ); } }
Next, You have to make 3 Screens. FirstScreen, SecondScreen and ThirdScreen. What you want to do is copy the below code of FirstScreen and make three screen dart files.
Replace FirstScreen text whereever you see in SecondScreen and ThirdScreen.
You can also download the source code at the bottom.
first_screen.dart
import 'package:flutter/material.dart'; class FirstScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('First Screen'), ), body: Padding( padding: const EdgeInsets.symmetric(horizontal: 150.0, vertical: 10), child: Text( 'First Screen', style: TextStyle(fontWeight: FontWeight.bold), ), ), ); } }
2. Flutter ListView Navigation + Passing Data
In this example, while navigating to DetailScreen, we also pass data. How will we do that?
- In this example, when the tap occurs, we use index of ListView and take Note data from _noteList and pass it to DetailScreen constructor.
- DetailScreen(note: _noteList[index]) :
//_noteList store Note Items. final List<Note> _noteList = [ Note( title: 'Note Title 1', content: 'Note Content 1', ), Note( title: 'Note Title 2', content: 'Note Content 2', ), Note( title: 'Note Title 3', content: 'Note Content 3', ) ]; ... .. . ListView.builder( itemCount: _noteList.length, itemBuilder: (context, index) { return ListTile( title: Text( _noteList[index].title, ), subtitle: Text( _noteList[index].content, ), onTap: () { //Navigator pushes the DetailScreen and Passes the note data through constructor. Navigator.push( context, MaterialPageRoute( builder: (context) => DetailScreen(note: _noteList[index]), ), ); }, ); }),
class DetailScreen extends StatelessWidget { final Note note; const DetailScreen({required this.note});
Let’s create the complete project… So make 3 dart Files.
- note.dart
- main.dart
- detail_screen.dart
note.dart
class Note { final String title; final String content; Note({required this.title, required this.content}); }
main.dart
import 'package:flutter/material.dart'; import 'detail_screen.dart'; import 'note.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'ListView Navigation + Passing Data', theme: ThemeData( primarySwatch: Colors.blue, ), home: ListScreen(), ); } } class ListScreen extends StatelessWidget { final List<Note> _noteList = [ Note( title: 'Note Title 1', content: 'Note Content 1', ), Note( title: 'Note Title 2', content: 'Note Content 2', ), Note( title: 'Note Title 3', content: 'Note Content 3', ) ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView Navigation + Passing Data'), ), body: ListView.builder( itemCount: _noteList.length, itemBuilder: (context, index) { return ListTile( title: Text( _noteList[index].title, ), subtitle: Text( _noteList[index].content, ), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => DetailScreen(note: _noteList[index]), ), ); }, ); }), ); } }
detail_screen.dart
import 'package:flutter/material.dart'; import 'note.dart'; class DetailScreen extends StatelessWidget { final Note note; const DetailScreen({required this.note}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Detail Screen'), ), body: Center( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ Text( note.title, style: TextStyle( fontWeight: FontWeight.bold, ), ), Text(note.content), ], ), ), ), ); } }
3.ListView Navigation – Passing Data Through RouteSettings
Just like constructor, you can also use RouteSettings to pass data. Just provide your data as value of arguments property.
final List<Note> _noteList = [ Note( title: 'Note Title 1', content: 'Note Content 1', ), Note( title: 'Note Title 2', content: 'Note Content 2', ), Note( title: 'Note Title 3', content: 'Note Content 3', ) ]; ..... ... .. . ListTile( title: Text( _noteList[index].title, ), subtitle: Text( _noteList[index].content, ), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => DetailScreen(), settings: RouteSettings(arguments: _noteList[index]), ), ); }, )
Okay. How to get this data from DetailScreen?
- Add below code inside build() method of DetailScreen.
final note = ModalRoute.of(context)!.settings.arguments as Note;
Exclamation mark – for null safety. If you are not using null safety, remove it.
note.dart
class Note { final String title; final String content; Note({required this.title, required this.content}); }
main.dart
import 'package:flutter/material.dart'; import 'detail_screen.dart'; import 'note.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter ListView Navigation - Passing Data', theme: ThemeData( primarySwatch: Colors.blue, ), home: ListScreen(), ); } } class ListScreen extends StatelessWidget { ListScreen({Key? key}) : super(key: key); final List<Note> _noteList = [ Note( title: 'Note Title 1', content: 'Note Content 1', ), Note( title: 'Note Title 2', content: 'Note Content 2', ), Note( title: 'Note Title 3', content: 'Note Content 3', ) ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView - Passing Data(RouteSettings)'), ), body: ListView.builder( itemCount: _noteList.length, itemBuilder: (context, index) { return ListTile( title: Text( _noteList[index].title, ), subtitle: Text( _noteList[index].content, ), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => DetailScreen(), settings: RouteSettings(arguments: _noteList[index]), ), ); }, ); }), ); } }
detail_screen.dart
import 'package:flutter/material.dart'; import 'note.dart'; class DetailScreen extends StatelessWidget { @override Widget build(BuildContext context) { final note = ModalRoute.of(context)!.settings.arguments as Note; return Scaffold( appBar: AppBar( title: Text('Detail Screen(RouteSettings)'), ), body: Center( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ Text( note.title, style: TextStyle( fontWeight: FontWeight.bold, ), ), Text(note.content), ], ), ), ), ); } }
4.ListView Navigation To A Statefulwidget With Data + Hero Animation
In this example, When the ListTile tapped, will move to a DetailScreen which extends StatefulWidget and also displays simple Hero animation.
- Hero tag value must be unique and you need to specify the same tag value in DetailScreen.
ListTile( leading: Hero( //unique tag - image name tag: note.image, child: CircleAvatar( backgroundImage: Image.asset('assets/${note.image}').image, ), ), title: Text( _noteList[index].title, ), subtitle: Text( _noteList[index].content, ), onTap: () { //Navigator pushes the DetailScreen with note data. Navigator.push( context, MaterialPageRoute( builder: (context) => DetailScreen(_noteList[index]), ), ); }, )
How to access this data in DetailScreen build method?
- Inside build() method, you can use widget with field name.
- Here, final note = widget.note.
class DetailScreen extends StatefulWidget { final Note note; DetailScreen(this.note); @override _DetailScreenState createState() => _DetailScreenState(); } class _DetailScreenState extends State<DetailScreen> { @override Widget build(BuildContext context) { //widget.field name final note = widget.note;
Let’s create the whole project. Source code of note.dart file is already given in above example.
Before that, you need to create assets directory to store image files. You can use your own image files or download our source code and use it . Also specify it in pubspec.yaml file.
main.dart
import 'package:flutter/material.dart'; import 'detail_screen.dart'; import 'note.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter ListView Navigation - Passing Data With Hero Animation', theme: ThemeData( primarySwatch: Colors.blue, ), home: ListScreen(), ); } } class ListScreen extends StatelessWidget { ListScreen({Key? key}) : super(key: key); final List<Note> _noteList = [ Note( title: 'Note Title 1', content: 'Note Content 1', image: 'nature.jpg', ), Note( title: 'Note Title 2', content: 'Note Content 2', image: 'island.jpg', ), Note( title: 'Note Title 3', content: 'Note Content 3', image: 'stones.jpg', ) ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ListView - Passing Data To Stateful Widget'), ), body: ListView.builder( itemCount: _noteList.length, itemBuilder: (context, index) { final note = _noteList[index]; return ListTile( leading: Hero( tag: note.image, child: CircleAvatar( backgroundImage: Image.asset('assets/${note.image}').image, ), ), title: Text( _noteList[index].title, ), subtitle: Text( _noteList[index].content, ), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => DetailScreen(_noteList[index]), ), ); }, ); }), ); } }
detail_screen.dart
import 'package:flutter/material.dart'; import 'note.dart'; class DetailScreen extends StatefulWidget { final Note note; DetailScreen(this.note); @override _DetailScreenState createState() => _DetailScreenState(); } class _DetailScreenState extends State<DetailScreen> { @override Widget build(BuildContext context) { final note = widget.note; return Scaffold( appBar: AppBar( title: Text('Detail Screen(RouteSettings)'), ), body: Center( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ Hero( tag: note.image, child: Image.asset('assets/${note.image}'), ), SizedBox(height: 8), Text( note.title, style: TextStyle( fontWeight: FontWeight.bold, ), ), Text(note.content), ], ), ), ), ); } }
Download Source Code
If you like this post, please share it with your family and friends.