Route là một lớp trừu tượng trong Flutter đại diện cho một màn hình hoặc trang riêng biệt trong lịch sử điều hướng của Navigator. Các triển khai cụ thể của Route — MaterialPageRoute, CupertinoPageRoute và PlatformRoute — xác định cách màn hình được hiển thị và hoạt ảnh nào được sử dụng trong quá trình chuyển đổi. Không giống như widget thông thường, Route có vòng đời riêng với các phương thức didPush, didPop, didReplace và didChangeNext. Theo Flutter API Reference (2026), mỗi Route quản lý ModalBarrier, tính đến các đặc điểm nền tảng cụ thể (vuốt lui trên iOS) và đảm bảo sự cô lập trạng thái giữa các màn hình.
Những điểm chính
Route là nền tảng của hệ thống điều hướng Flutter. Mỗi màn hình mà người dùng thấy trong ứng dụng được đại diện bởi một đối tượng Route nằm trong ngăn xếp Navigator. Route trừu tượng hóa màn hình khỏi mã điều khiển: Navigator thêm và xóa Route, trong khi bên trong Route là giao diện mà người dùng thấy. Kiến trúc này tách biệt trách nhiệm giữa điều hướng và hiển thị.
Không giống như việc thay thế widget đơn giản, Route cung cấp các dịch vụ không có sẵn cho widget thông thường: ModalBarrier (làm mờ nền khi hộp thoại mở), kiểm soát hoạt ảnh vào và ra, xử lý nút quay lại phần cứng trên Android và tích hợp với hoạt ảnh Hero để chuyển đổi mượt mà giữa các màn hình.
Theo Flutter Cookbook (2026), Route là yếu tố chính cho hoạt ảnh Hero: một widget Hero trên Route này tự động tạo hoạt ảnh chuyển đổi đến widget Hero trên Route tiếp theo, tạo hiệu ứng phần tử “ bay”. Điều này có thể thực hiện được chính xác vì Route giữ cả hai màn hình trong Overlay trong suốt quá trình hoạt ảnh.
Route là nền tảng cho cả ứng dụng di động đơn giản (qua Navigator 1.0) và các kịch bản phức tạp với liên kết sâu (Navigator 2.0). Trong Navigator 2.0, Route đại diện cho một Page mà RouterDelegate chuyển đổi từ cấu hình route. Do đó, hiểu Route là cần thiết để làm việc với bất kỳ hệ thống điều hướng Flutter nào — bất kể phương pháp hoặc gói đã chọn.
Flutter cung cấp một số triển khai Route tích hợp sẵn, mỗi loại điều chỉnh hành vi cho một nền tảng cụ thể. Chọn đúng loại Route ảnh hưởng đến trải nghiệm người dùng: hoạt ảnh Material trên Android và hoạt ảnh Cupertino trên iOS tạo cảm giác ứng dụng “ gốc”.
| Loại Route | Hoạt ảnh | Nền tảng | Đặc điểm |
|---|---|---|---|
| MaterialPageRoute | Trượt từ dưới lên trên | Android, máy tính để bàn | Bóng khi chuyển đổi, xử lý SafeArea tự động |
| CupertinoPageRoute | Trượt từ phải sang trái | iOS, iPadOS | Cử chỉ vuốt lui, nền trong suốt khi chuyển đổi |
| PlatformRoute | Tự động chọn | Tất cả nền tảng | Chọn loại dựa trên TargetPlatform |
| PageRouteBuilder | Tùy chỉnh | Tất cả nền tảng | Kiểm soát hoàn toàn hoạt ảnh qua AnimationController |
MaterialPageRoute là triển khai Route được sử dụng nhiều nhất. Nó tạo hoạt ảnh cho màn hình mới đi vào từ dưới lên trên với sự xuất hiện dần dần. Khi thoát, màn hình tạo hoạt ảnh từ trên xuống dưới, trở về vị trí ban đầu. Thanh công cụ (AppBar) và thân màn hình tạo hoạt ảnh riêng biệt, tạo hiệu ứng phân cấp.
CupertinoPageRoute bắt chước UINavigationController từ iOS. Màn hình mới đi vào từ bên phải, che phủ màn hình trước đó. Đặc điểm chính là hỗ trợ cử chỉ vuốt lui tương tác, được triển khai qua CupertinoBackGestureDetector. Cử chỉ này được xử lý ngay cả giữa hoạt ảnh, cung cấp hành vi tự nhiên quen thuộc với người dùng iPhone.
Route có vòng đời riêng, khác với vòng đời của StatefulWidget thông thường. Hiểu chu kỳ này là cần thiết để khởi tạo dữ liệu đúng cách, đăng ký luồng và giải phóng tài nguyên khi đóng màn hình.
Vòng đời của Route bao gồm bốn giai đoạn chính. Chuyển tiếp — Route được tạo và tạo hoạt ảnh khi vào (didPush được gọi). Hoạt động — Route được hiển thị đầy đủ và tương tác với người dùng. Không hoạt động — Route khác che màn hình hiện tại (hộp thoại, trang tính dưới), nhưng Route vẫn ở trong ngăn xếp. Bị hủy — Route bị xóa khỏi ngăn xếp và bị hủy, didPop và dispose được gọi.
Các phương thức vòng đời của Route có thể được ghi đè trong triển khai tùy chỉnh. Ví dụ: didPop được gọi khi Route bị xóa khỏi ngăn xếp — tại đây bạn có thể lưu dữ liệu nháp. didChangeNext được gọi khi Route tiếp theo trong ngăn xếp thay đổi — hữu ích để cập nhật UI khi lịch sử điều hướng thay đổi.
Theo Flutter API Route.didPop (2026), điều quan trọng là không nhầm lẫn vòng đời của Route với vòng đời của State bên trong Route. StatefulWidget bên trong Route có initState và dispose riêng, được gọi trong các giai đoạn Chuyển tiếp và Bị hủy tương ứng. Route sống lâu hơn State bên trong — Route vẫn ở trong Overlay ngay cả khi các widget của nó tạm thời bị ẩn bởi Route khác.
Route cung cấp cơ chế truyền dữ liệu cả khi nhập (khi tạo) và khi xuất (khi hoàn thành). Truyền dữ liệu đúng cách qua Route loại bỏ nhu cầu về biến toàn cục và InheritedWidget, làm cho điều hướng an toàn kiểu và có thể dự đoán được.
Để truyền dữ liệu đến màn hình mới, hãy sử dụng hàm tạo của widget nhận hoặc tham số arguments trong Navigator.pushNamed. Bên trong Route, dữ liệu có thể truy cập qua RouteSettings.arguments, được lưu trữ trong đối tượng Route. Cách tiếp cận này hoạt động cho tất cả các loại Route — MaterialPageRoute, CupertinoPageRoute và triển khai tùy chỉnh.
Để trả về dữ liệu, hãy sử dụng đối số thứ hai của Navigator.pop(context, result). Navigator.push trả về Future
Khi gọi trực tiếp Navigator.push với MaterialPageRoute, dữ liệu được truyền qua hàm tạo của màn hình đích. MethodChannel không được sử dụng — đây là tương tác Dart thuần túy. Cách tiếp cận này được ưu tiên để truyền an toàn kiểu các đối tượng phức tạp.
Hãy xem xét một ví dụ về tạo Route tùy chỉnh với hoạt ảnh và truyền dữ liệu riêng. PageRouteBuilder cho phép định nghĩa hoạt ảnh vào và ra với kiểm soát hoàn toàn về đường cong hoạt ảnh và thời lượng.
// Route tùy chỉnh với hoạt ảnh trượt
Navigator.push(context, PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return DetailPage(productId: '42');
},
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 0.3);
const end = Offset.zero;
final tween = Tween(begin: begin, end: end);
final offsetAnimation = animation.drive(tween);
return SlideTransition(position: offsetAnimation, child: child);
},
transitionDuration: const Duration(milliseconds: 400),
));
// Trả về dữ liệu từ màn hình
ElevatedButton(
onPressed: () => Navigator.of(context).pop({'selected': true, 'id': '42'}),
child: const Text('Chọn'),
);
// Nhận kết quả trên màn hình gọi
final result = await Navigator.push(context, MaterialPageRoute(
builder: (context) => const SelectionPage(),
));
if (result != null) {
print('Đã chọn: ${result['selected']}');
}
Trong ví dụ, PageRouteBuilder định nghĩa hoạt ảnh trượt từ dưới lên tùy chỉnh với độ trong suốt. transitionDuration đặt tốc độ hoạt ảnh. Mã cũng minh họa truyền kết quả: màn hình chi tiết trả về Map với lựa chọn của người dùng và màn hình gọi nhận dữ liệu này qua Future từ push. Route đảm bảo sự cô lập hoàn toàn: các bản nháp trên màn hình chi tiết không ảnh hưởng đến trạng thái danh sách.
Các câu hỏi thường gặp
Route là một đối tượng quản lý màn hình ở cấp độ điều hướng: nó lưu trữ hoạt ảnh, ModalBarrier và vòng đời. Widget là mô tả của một phần giao diện. Route chứa Widget bên trong nó, nhưng cũng cung cấp các dịch vụ (lớp Overlay, hoạt ảnh Hero) không có sẵn cho widget thông thường. Một Route có thể chứa một hệ thống phân cấp phức tạp các widget với bất kỳ độ sâu nào.
Sử dụng PageRouteBuilder với các tham số pageBuilder (xây dựng màn hình) và transitionsBuilder (định nghĩa hoạt ảnh). Trong transitionsBuilder, có sẵn animation (0.0–1.0) và secondaryAnimation cho các hoạt ảnh song song. Để kiểm soát hoàn toàn, hãy tạo một lớp con của Route và ghi đè buildPage, createAnimationController và buildTransitions, cung cấp quyền truy cập vào AnimationController cấp thấp.
Để truyền đối tượng phức tạp, hãy sử dụng hàm tạo của màn hình đích khi gọi trực tiếp Navigator.push hoặc tham số arguments với pushNamed. Đảm bảo đối tượng có thể tuần tự hóa (Map, JSON hoặc lớp tùy chỉnh). Để truyền an toàn kiểu trong Flutter, hãy sử dụng mô hình freezed hoặc json_serializable, đảm bảo giải tuần tự hóa chính xác khi truyền qua RouteSettings.
Route.dispose không được gọi nếu Route vẫn ở trong ngăn xếp Navigator. Ví dụ: khi mở Route mới, Route cũ chuyển sang trạng thái không hoạt động nhưng không bị hủy — nó vẫn ở trong ngăn xếp để quay lại nhanh. Dispose chỉ được gọi khi Route bị xóa khỏi ngăn xếp qua pop, pushReplacement hoặc pushAndRemoveUntil. Để giải phóng tài nguyên, hãy sử dụng dispose của State bên trong Route, không phải dispose của chính Route.
Sử dụng ModalRoute.of(context) để lấy Route hiện tại từ BuildContext. Thuộc tính ModalRoute.isActive cho biết Route có phải là màn hình hiện đang hiển thị hay không. ModalRoute.isCurrent — true nếu Route là đỉnh của ngăn xếp. Để quan sát các thay đổi của ngăn xếp, hãy đăng ký các quan sát viên Navigator qua RouteAware và RouteObserver, thông báo về các thay đổi Route hoạt động.
Tóm tắt
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm