© Khmer Angkor Academy - sophearithput168

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() ដើម្បីត្រឡប់ទៅទំព័រមុន។