Push and pop screens with Navigator.push and pop, pass data through constructors, and retrieve a result when the screen closes.
Open this lesson in KodokonFlutter manages your screens as a stack: Navigator.push places a new screen on top, Navigator.pop removes the top one and reveals the previous one. Each screen is a route, and MaterialPageRoute provides the platform's native transition. Android's back button calls pop for you, without a single line of code.
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home')),
body: Center(
child: FilledButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const DetailScreen(
productName: 'Headphones',
);
},
),
);
},
child: const Text('View product'),
),
),
);
}
}To pass data to the next screen, there is no magic mechanism: the destination screen is a widget like any other, and it receives its data through its constructor. It's typed, explicit, and the compiler catches you if a field is missing. Note that the AppBar of the pushed screen shows the back button without you writing anything.
import 'package:flutter/material.dart';
class DetailScreen extends StatelessWidget {
const DetailScreen({
super.key,
required this.productName,
});
final String productName;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(productName)),
body: Center(
child: FilledButton(
onPressed: () {
Navigator.pop(context, true);
},
child: const Text('Add to cart'),
),
),
);
}
}Navigator.push returns a Future that completes when the screen is closed, with the value passed to pop. You can therefore await the result of a screen: a confirmation, an item chosen from a list, a filled-in form. The generic type push<bool> documents what you expect to get back.
import 'package:flutter/material.dart';
Future<void> openDetail(BuildContext context) async {
final added = await Navigator.push<bool>(
context,
MaterialPageRoute<bool>(
builder: (context) {
return const DetailScreen(
productName: 'Headphones',
);
},
),
);
if (!context.mounted) return;
final message = (added ?? false)
? 'Product added to cart'
: 'No product added';
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}