
Tóm tắt: trong bài viết này các bạn sẽ được học về Flutter navigation để điều hướng từ 1 màn hình này qua màn hình khác và quay trở lại
Giới thiệu về Flutter navigation
Thông thường, ứng dụng chứa nhiều màn hình để hiển thị thông tin khác nhau. Ví dụ: ứng dụng thương mại điện tử có thể có màn hình hiển thị danh sách sản phẩm. Khi người dùng chạm vào một sản phẩm, một màn hình mới sẽ hiển thị chi tiết sản phẩm
Flutter navigation quản lý các màn hình dưới dạng một ngăn xếp và hiển thị màn hình nằm trên cùng của ngăn xếp.
Stack
Một stack là một cấu trúc dữ liệu đóng vai trò là tập hợp các mục với hai thao tác chính:
- Push: thêm một mục vào ngăn xếp.
- Pop: xóa mục được thêm gần đây nhất khỏi ngăn xếp.
Thứ tự mà một mục được thêm vào hoặc xóa khỏi ngăn xếp được gọi là vào sau, ra trước hoặc viết tắt là LIFO.
Navigator
Flutter navigation hoạt động giống như một ngăn xếp các màn hình. Trong Flutter, các màn hình và trang thường được gọi là các tuyến đường, là các widget.
Flutter sử dụng đối tượng Navigator để điều hướng từ tuyến này sang tuyến khác. Đối tượng Navigator giống như một tập hợp các tuyến đường, có hai phương thức chính:
- push() – navigate to a new route by adding a route to the stack .
- pop() – xóa tuyến đường hiện tại khỏi ngăn xếp
Ví dụ Flutter navigation
Ví dụ sau đây cho thấy cách sử dụng đối tượng Navigator để điều hướng đến một tuyến đường mới và quay lại
import 'package:flutter/material.dart'; void main() { runApp( const MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Navigation', home: HomeScreen(), ) ); } class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home screen'), ), body: Center( child: ElevatedButton( child: const Text('Go to the detail screen'), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const DetailScreen()), ); }, ), ), ); } } class DetailScreen extends StatelessWidget { const DetailScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Detail screen'), ), body: Center( child: ElevatedButton( onPressed: () { Navigator.pop(context); }, child: const Text('Go back!'), ), ), ); } }
Nó làm việc như thế nào.
Đầu tiên, tạo 2 màn hình: HomeScreen
và DetailScreen
.
Tiếp theo, màn hình HomeScreen
có 1 button. Khi nhấp vào button, gọi phương thức push()
của đối tượng Navigator để điều hướng tới 1 tuyến đường mới.
onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const SecondScreen()), ); }
Phương thức push()
chấp nhận tham số đầu tiên là BuildContext
hiện tại và tham số thứ 2 là một đối tượng MaterialPageRoute
.
Đối tượng MaterialPageRoute
chỉ định tuyến đường mới được điều hướng tới.
Thứ ba, màn hình DetailScreen
cũng có 1 nút. Khi nút được bấm, quay trở lại màn hình HomeScreen
bởi việc gọi phương thức pop()
của đối tượng Navigato
r:
Navigator.pop(context);
Phương thức pop()
chấp nhận tham số là một context của BuildContext
hiện tại.
Gởi dữ liệu tới 1 tuyến đường mới
Ví dụ sau minh họa cách gửi một chuỗi từ HomeScreen đến DetailScreen:
import 'package:flutter/material.dart'; void main() { runApp(const MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Navigation', home: HomeScreen(), )); } class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home screen'), ), body: Center( child: ElevatedButton( child: const Text('Go to the detail screen'), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const DetailScreen( message: 'This is a message from the home screen'), ), ); }, ), ), ); } } class DetailScreen extends StatelessWidget { final String message; const DetailScreen({super.key, required this.message}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Detail screen'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(message), ElevatedButton( onPressed: () { Navigator.pop(context); }, child: const Text('Go back!'), ), ], ), ), ); } }
Nó làm việc như thế nào.
Đầu tiên, thêm 1 thuộc tính message
tới màn hình DetailScreen
và một hàm khơi tạo chấp nhận thêm 1 tham số đầu this.message
vào const DetailScreen({super.key, required this.message});
Thứ 2, thêm 1 Text
widget để hiện thị thuộc tính message lên
Thứ 3, Khi gọi phương thức push()
của đối tượng Navigator
, gởi một chuỗi tới hàm khởi tạo DetailScreen
.
Gởi dữ liệu trở lại tuyến đường trước đó
Ví dụ sau sẽ minh họa làm thế nào để truyền dữ liệu từ màn hình DetailScreen
trở lại màn hình HomeScreen
:
import 'package:flutter/material.dart'; void main() { runApp(const MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Navigation', home: HomeScreen(), )); } class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home screen'), ), body: Center( child: ElevatedButton( child: const Text('Go to the detail screen'), onPressed: () async { var message = await Navigator.push( context, MaterialPageRoute( builder: (context) => const DetailScreen( message: 'This is a message from the home screen' ), ), ); print(message); }, ), ), ); } } class DetailScreen extends StatelessWidget { final String message; const DetailScreen({super.key, required this.message}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Detail screen'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(message), ElevatedButton( onPressed: () { Navigator.pop(context, 'This is a message from the Detail screen'); }, child: const Text('Go back!'), ), ], ), ), ); } }
Đầu tiên, truyền 1 chuỗi tới tham số thứ 2 của phương thức pop()
của đối tượng Navigator từ màn hình DetailScreen
:
onPressed: () { Navigator.pop( context, 'This is a message from the Detail screen' ); }
Thứ 2, thay đổi hàm onPressed
thành hàm async bởi vì chúng ta sẽ sử dụng từ khóa await bên trong nó.
Phương thức push()
trả về 1 đối tượng Future
vì vậy chúng ta sử dụng từ khóa await
để đợi dữ liệu trước khi nhận được dữ liệu trả về từ màn hình DetailScreen
.
Để demo cho việc này, chúng tôi in ra chuỗi trả về.
onPressed: () async { var message = await Navigator.push( context, MaterialPageRoute(builder: (context) => const DetailScreen(message: 'This is a message from the home screen')), ); print(message); }
Kết luận
- Sử dụng đối tượng
Navigator
để điều hướng từ 1 tuyến đường tới 1 tuyến đường khác. - Sử dụng phương thức
push()
của đối tượng Navigator để điều hướng tới 1 tuyến đường mới. - Sử dụng phương thức
pop()
của đối tượng Navigator để quay trở lại tuyến đường trước đó.
Nguồn: https://www.darttutorial.org/flutter-tutorial/flutter-navigation/
Happy coding 🙂