Mục tiêu:
- Hiểu cách Flutter quản lý navigation theo cơ chế stack
- Nắm được cách sử dụng
Navigator.push
vàNavigator.pop
- Biết cách truyền dữ liệu sang màn hình khác và nhận dữ liệu trả về
- Làm quen với việc thiết kế ứng dụng nhiều màn hình
1. Navigation trong Flutter là gì
Trong hầu hết các ứng dụng, người dùng không chỉ làm việc trên một màn hình duy nhất. Navigation (điều hướng) cho phép ứng dụng di chuyển từ màn hình này sang màn hình khác. Flutter quản lý navigation bằng một ngăn xếp (stack):
- Khi mở một trang mới, Flutter thực hiện push route đó vào stack.
- Khi quay lại, Flutter thực hiện pop để lấy trang trên cùng ra khỏi stack.
Cơ chế này tương tự như thao tác với chồng sách: thêm một quyển mới đặt lên trên (push), hoặc bỏ quyển trên cùng ra ngoài (pop).

2. Navigator.push và Navigator.pop
Cách cơ bản nhất để điều hướng giữa các màn hình là dùng Navigator.push
và Navigator.pop
.
Ví dụ:
// Màn hình chính
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
},
child: Text('Đi tới trang 2'),
);
// Màn hình thứ hai
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Quay lại'),
);
Trong ví dụ này:
Navigator.push
đưaSecondScreen
lên stack, ứng dụng hiển thị màn hình mới.Navigator.pop
xóa màn hình hiện tại và quay về màn hình trước đó.

3. Truyền dữ liệu giữa các màn hình
Khi di chuyển sang màn hình mới, chúng ta thường muốn truyền dữ liệu. Điều này thực hiện bằng cách truyền tham số vào constructor của màn hình mới.
// Màn hình 1
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(data: "Xin chào"),
),
);
// Màn hình 2
class DetailScreen extends StatelessWidget {
final String data;
DetailScreen({required this.data});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Chi tiết")),
body: Center(child: Text(data)),
);
}
}
Ở đây, màn hình 1 gửi chuỗi "Xin chào"
sang DetailScreen
. Màn hình 2 nhận giá trị này qua constructor và hiển thị.

4. Nhận dữ liệu trả về từ màn hình khác
Một tình huống phổ biến là mở một màn hình phụ để nhập dữ liệu, sau đó trả kết quả về màn hình trước. Flutter cho phép làm điều này nhờ Navigator.pop
có tham số.
// Màn hình 1
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => InputScreen()),
);
print("Kết quả nhận được: $result");
// Màn hình 2
Navigator.pop(context, "Dữ liệu trả về");
Trong ví dụ:
- Màn hình 1 gọi
Navigator.push
và chờ kết quả. - Màn hình 2 gọi
Navigator.pop
với giá trị"Dữ liệu trả về"
. - Màn hình 1 nhận kết quả này và sử dụng tiếp.

5. Ví dụ thực hành: Ứng dụng sản phẩm
Tạo ứng dụng có 2 màn hình:
- Màn hình danh sách sản phẩm: hiển thị danh sách sản phẩm bằng ListView. Khi nhấn vào một sản phẩm, mở trang chi tiết.
- Màn hình chi tiết sản phẩm: hiển thị thông tin chi tiết, có nút “Thêm vào giỏ hàng”. Khi bấm nút này, dùng
Navigator.pop
trả về trạng thái “đã thêm vào giỏ”.
Ở màn hình danh sách, sau khi nhận kết quả trả về, có thể hiển thị thông báo hoặc cập nhật giỏ hàng.
6. Navigation nâng cao
Với các ứng dụng nhỏ, Navigator.push
và pop
là đủ. Tuy nhiên, khi ứng dụng có nhiều màn hình hoặc yêu cầu phức tạp hơn, nên dùng các thư viện quản lý route:
- go_router: thư viện chính thức, tích hợp tốt với Flutter.
- auto_route: mạnh mẽ, hỗ trợ code generation để tự động tạo route.
Những thư viện này giúp code rõ ràng, dễ quản lý, và hỗ trợ deep linking, nested navigation.
7. Bài tập thực hành
- Tạo ứng dụng có 3 màn hình: Trang chủ → Trang danh sách sản phẩm → Trang chi tiết sản phẩm.
- Truyền dữ liệu sản phẩm từ danh sách sang chi tiết.
- Khi bấm “Mua hàng”, trả về trạng thái để Trang chủ cập nhật tổng số sản phẩm đã mua.
Sign up