Navigation
Navigation ក្នុង Flutter
Navigation ប្រើសម្រាប់ផ្លាស់ទីតាំងរវាងទំព័រ (screens/routes) ផ្សេងៗក្នុង app។ Flutter ប្រើ Navigator widget ដើម្បីគ្រប់គ្រង navigation stack។
📚 Navigation Theory
Stack-based Navigation:
Flutter navigation ដំណើរការដូច Stack data structure (LIFO - Last In, First Out):
Navigation Stack (រូបភាពពីក្រោមឡើងលើ)
[Page D] ← Current screen (top of stack)
[Page C]
[Page B]
[Page A] ← Root screen (bottom of stack)
Operations:
• push() - បន្ថែម screen ថ្មីនៅលើ stack
• pop() - យក screen បច្ចុប្បន្នចេញពី stack
• pushReplacement() - ជំនួសថ្មីជំនួស current screen
• popUntil() - pop រហូតដល់ screen ជាក់លាក់
Navigation Methods:
Method | Action | Use Case |
---|---|---|
push() | Add new screen on top | ទៅទំព័រថ្មី (មាន back button) |
pop() | Remove current screen | ត្រឡប់ទៅទំព័រមុន |
pushReplacement() | Replace current screen | Login → Home (មិនត្រឡប់ទៅ Login) |
pushAndRemoveUntil() | Clear stack and push | Logout → Login (clear all screens) |
popUntil() | Pop to specific screen | ត្រឡប់ទៅ Home ពី nested screens |
🚀 Basic Navigation
Method 1: Direct Navigation (Anonymous Routes)
ងាយស្រួលបំផុត សម្រាប់ apps តូចៗ:
📱 Navigator.push()
// ទៅទំព័រថ្មី
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
// ត្រឡប់មកវិញ
Navigator.pop(context);
🔄 Named Routes
Named Routes គឺជា approach ល្អបំផុតសម្រាប់ apps ធំៗ។ វាងាយស្រួលគ្រប់គ្រង និង maintain។
Advantages of Named Routes:
- ✅ Centralized route management
- ✅ ងាយស្រួល navigate ពីកន្លែងណាក៏បាន
- ✅ Support deep linking
- ✅ Easy to pass arguments
- ✅ Better code organization
Setup Named Routes:
// main.dart
MaterialApp(
initialRoute: '/', // ទំព័រដំបូង
routes: {
'/': (context) => HomePage(),
'/profile': (context) => ProfilePage(),
'/settings': (context) => SettingsPage(),
'/details': (context) => DetailsPage(),
},
// Handle unknown routes
onUnknownRoute: (settings) {
return MaterialPageRoute(
builder: (context) => NotFoundPage(),
);
},
);
// Navigate using name
Navigator.pushNamed(context, '/profile');
// With arguments
Navigator.pushNamed(
context,
'/details',
arguments: {'id': 123, 'title': 'Product'},
);
Receiving Arguments:
class DetailsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Get arguments
final args = ModalRoute.of(context)!.settings.arguments as Map;
return Scaffold(
appBar: AppBar(
title: Text(args['title']),
),
body: Text('ID: ' + args['id'].toString()),
);
}
}
↩️ Returning Data
អ្នកអាច return data ពីទំព័រថ្មីមកទំព័រចាស់៖
// Screen A: Navigate and wait for result
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionPage()),
);
print('User selected: ' + result.toString());
// Screen B: Return data when popping
Navigator.pop(context, 'Selected Value');
🎯 Advanced Navigation Patterns
1. Bottom Navigation Bar
class MainScreen extends StatefulWidget {
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
int _currentIndex = 0;
final List<Widget> _screens = [
HomeScreen(),
SearchScreen(),
ProfileScreen(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: _screens[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
),
],
),
);
}
}
2. Drawer Navigation
Scaffold(
appBar: AppBar(title: Text('Home')),
drawer: Drawer(
child: ListView(
children: [
DrawerHeader(
decoration: BoxDecoration(color: Colors.blue),
child: Text('Menu', style: TextStyle(color: Colors.white)),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () {
Navigator.pop(context); // Close drawer
Navigator.pushNamed(context, '/');
},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Settings'),
onTap: () {
Navigator.pop(context);
Navigator.pushNamed(context, '/settings');
},
),
],
),
),
body: Center(child: Text('Content')),
);
3. Tab Navigation
DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
title: Text('Tabs'),
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.home), text: 'Home'),
Tab(icon: Icon(Icons.star), text: 'Favorites'),
Tab(icon: Icon(Icons.person), text: 'Profile'),
],
),
),
body: TabBarView(
children: [
HomeTab(),
FavoritesTab(),
ProfileTab(),
],
),
),
);
💡 Best Practice: ប្រើ Named Routes សម្រាប់ apps ធំៗ។ ប្រើ direct navigation (push/pop) សម្រាប់ navigation តូចៗក្នុង feature module។
⚠️ ចំណាំ: Navigator 2.0 (Declarative Navigation) មានក្នុង Flutter ដែរ ប្រើសម្រាប់ complex navigation scenarios និង deep linking។ ប៉ុន្តែ Navigator 1.0 គ្រប់គ្រាន់សម្រាប់ apps ភាគច្រើន។
🔄 Named Routes
// main.dart (ការដាក់រចនាសម្ព័ន្ធពីមុន)
MaterialApp(
routes: {
'/': (context) => HomePage(),
'/second': (context) => SecondPage(),
},
);
// ប្រើ named routes
Navigator.pushNamed(context, '/second');
💡 ជំនួយ: ប្រើ Navigator.pop() ដើម្បីត្រឡប់ទៅទំព័រមុន។