Nguồn : [Navigation and routing Flutter](https://docs.flutter.dev/ui/navigation)
I. TỔNG QUAN
  • Navigator hỗ trợ PushPop Route
onPressed: () {
 Navigator.of(context).push(
 //Nếu style của app là Material
 //Sử dụng MaterialPageRoute là tham số cho hàm push.
 MaterialPageRoute(
 builder: (context) => const SongScreen(song: song),
 ),
 );
},
  • Nếu bạn không muốn dùng Screen, bạn có thể config name để routing.
@override
 Widget build(BuildContext context) {
 return MaterialApp(
 routes: {
 '/': (context) => HomeScreen(),
 '/details': (context) => DetailScreen(),
 },
 );
}
  • NOTE : Theo document Flutter, k nên dùng nó vì khi sử dụng deeplink nó luôn Push một Route mới mà k quan tâm app bạn đang hiển thị route nào.
  • Dùng Router
    • Ưu điểm của nó là khi deeplink , nó k tạo ra route mới route đó đã có.
    • Để dùng nó, MaterialApp có tạo săn contructors là router, với tham số là routerConfig
    MaterialApp.router(
     routerConfig: GoRouter(
     // …
     )
     );
    
  • NOTE : GoRouter là một gói hỗ trợ routing, nếu bạn k thích dùng nó mà muốn tự custom vẫn được. Orverride lại 2 hàm này RouteInformationParserRouterDelegate
  • Router và Navigator nó thiết kế để tương thích với nhau, nên hàm pushpop vẫn dùng được.
II. Làm Việc Với Tabs
  • Dùng widget DefaultTabController
    • length : Xác định số lượng tab
    • child : Nên là một Scaffold widget.
  • Tabbar : Dùng để khai báo các item Tab.
  • TabbarView : Dùng để khai báo content của Tab.
import 'package:flutter/material.dart';

void main() {
  runApp(const TabBarDemo());
}

class TabBarDemo extends StatelessWidget {
  const TabBarDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController( 
        length: 3, // Số Lượng Tab
        child: Scaffold(
          appBar: AppBar(
            bottom: const TabBar(
              tabs: [
                Tab(icon: Icon(Icons.directions_car)),
                Tab(icon: Icon(Icons.directions_transit)),
                Tab(icon: Icon(Icons.directions_bike)),
              ],
            ),
            title: const Text('Tabs Demo'),
          ),
          body: const TabBarView(
            children: [
              Icon(Icons.directions_car),
              Icon(Icons.directions_transit),
              Icon(Icons.directions_bike),
            ],
          ),
        ),
      ),
    );
  }
}
III. Navigate Đến Màn Hình Mới Và Trở Lại.
  • Dùng hàm pushpop
// Within the `FirstRoute` widget
 onPressed: () {
 Navigator.push(
 context,
 MaterialPageRoute(builder: (context) => const SecondRoute()),
 );
 }
// Within the SecondRoute widget
onPressed: () {
 Navigator.pop(context);
}
IV. GỬI VÀ NHẬN DATA
  • Gửi Data :
    • Cách 1 : Truyền qua contructors, Cách này dùng chán, mỗi lần truyền phải contructor để nhận data, tự tham khảm document.
    • Cách 2 : Dùng thông qua Arguments

      MaterialPageRoute(
       builder: (context) => const DetailScreen(),
       // Pass the arguments as part of the RouteSettings. The
       // DetailScreen reads the arguments from these settings.
       settings: RouteSettings(
       //Truyền data tại đây. Data là một Object muốn truyền gì cũng được :v
       arguments: todos[index], 
      ),
      
      • Màn hình mới thì lấy nó ra như thế này :
      //Phải ép kiểu về, agruments cho chỉ biết mỗi Object.
      final todo = ModalRoute.of(context)!.settings.arguments as Todo;
      
  • Nhận Data
    • Hàm pop của Navigator nó hỗ trợ, cứ truyền data muốn trả về thôi

      Navigator.pop(context, data);
      
    • Muốn nhận data trả được trả về thì lúc bạn push phải đợi. Cụ thể là phải await nó =))

      //Thằng result chính là data từ màn hình vừa trả về
      final result = await Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => const SelectionScreen()),
      );
      
IV. Drawer
  • Nó là cái hamburger menu đấy.
  • Để thực hiện thì làm theo các bước
    1. Khai báo widget Scaffold
    2. Setting widget Drawer vào thuộc tính drawer của Scaffold
    3. Layout Drawer thông qua thuộc tính child
    4. Navigator.pop(context) để đóng drawer.
  • Đoạn code dưới đây mình chỉ mổ ta phần chính của Drawer, muốn xem full thì vào đây

    @override
     Widget build(BuildContext context) {
     return Scaffold(
     appBar: AppBar(title: Text(widget.title)),
     body: Center(
     child: _widgetOptions[_selectedIndex],
     ),
     // Widget Drawer
     drawer: Drawer(
     // Child nó yêu cầu widget, nên bạn dùng widget nào cùng được
     // Nhưng để hợp lí thì mình dùng ListView để hiển thị các item
     child: ListView(
     // Important: Remove any padding from the ListView.
     padding: EdgeInsets.zero,
     children: [
     //Nó có widget DrawerHeader để làm header cho drawer
     const DrawerHeader(
     decoration: BoxDecoration(
     color: Colors.blue,
     ),
     child: Text('Drawer Header'),
     ),
     ListTile(
     title: const Text('Home'),
     selected: _selectedIndex == 0,
     onTap: () {
     // Update the state of the app
     _onItemTapped(0); 
    //Muốn đóng drawer thì dùng hàm pop thôi
     Navigator.pop(context);
     },
     ),
     ListTile(
     title: const Text('Business'),
     selected: _selectedIndex == 1,
     onTap: () {
     // Update the state of the app
     _onItemTapped(1); 
    //Muốn đóng drawer thì dùng hàm pop thôi
     Navigator.pop(context);
     },
     ),
     ListTile(
     title: const Text('School'),
     selected: _selectedIndex == 2,
     onTap: () {
     // Update the state of the app
     _onItemTapped(2);
     //Muốn đóng drawer thì dùng hàm pop thôi
     Navigator.pop(context);
     },
     ),
     ],
     ),
     ),
     );
     }
    
  • Phần này nói sau, đang study chưa cần ưu tiên.