Bỏ qua để đến nội dung

🚀 Navigation cơ bản

Flutter sử dụng Navigator để quản lý stack các routes (screens):

┌─────────────┐
│ Screen C │ ← Top of stack (visible)
├─────────────┤
│ Screen B │
├─────────────┤
│ Screen A │ ← Bottom of stack
└─────────────┘

Thêm screen mới lên stack:

Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondScreen(),
),
);

Shorthand:

Navigator.of(context).push(
MaterialPageRoute(builder: (_) => SecondScreen()),
);

Quay lại screen trước:

Navigator.pop(context);

Hoặc:

Navigator.of(context).pop();

class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('First Screen')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => SecondScreen()),
);
},
child: Text('Go to Second'),
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Second Screen')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
),
);
}
}

Thay thế screen hiện tại (không thể back):

Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => HomeScreen()),
);

Use case: Sau khi login, replace LoginScreen bằng HomeScreen.


Push screen mới và xóa các screens trước đó:

// Xóa tất cả và push Home
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => HomeScreen()),
(route) => false, // Xóa tất cả
);
// Xóa đến khi gặp route có tên '/home'
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => ProfileScreen()),
ModalRoute.withName('/home'),
);

Use case: Logout - clear stack và về LoginScreen.


Pop về screen cụ thể:

// Pop về screen đầu tiên
Navigator.popUntil(context, (route) => route.isFirst);
// Pop về named route
Navigator.popUntil(context, ModalRoute.withName('/home'));

Kiểm tra có thể pop không:

if (Navigator.canPop(context)) {
Navigator.pop(context);
}
// Hoặc
Navigator.maybePop(context); // Pop nếu có thể

WillPopScope(
onWillPop: () async {
// Return true để pop, false để không
final shouldPop = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text('Exit?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text('No'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text('Yes'),
),
],
),
);
return shouldPop ?? false;
},
child: Scaffold(...),
)

Flutter 3.12+: Dùng PopScope thay cho WillPopScope

PopScope(
canPop: false,
onPopInvoked: (didPop) async {
if (didPop) return;
// Show confirmation dialog
},
child: Scaffold(...),
)

Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => SecondScreen(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
// Fade transition
return FadeTransition(opacity: animation, child: child);
// Slide transition
// return SlideTransition(
// position: Tween<Offset>(
// begin: Offset(1.0, 0.0),
// end: Offset.zero,
// ).animate(animation),
// child: child,
// );
},
),
);

Method Mô tả
push Thêm screen vào stack
pop Quay lại screen trước
pushReplacement Thay thế screen hiện tại
pushAndRemoveUntil Push và xóa các screens
popUntil Pop về screen cụ thể
canPop Kiểm tra có thể pop
maybePop Pop nếu có thể