---
# System prepended metadata

title: Navigation router

---

# Navigation router

## ButtomTabs 底部的切換頁

![](https://i.imgur.com/0usXoEW.png =40%x)


會使用到的內建widget：
1. BottomNavigationBar
2. BottomNavigationBarItem

#### main.dart
```java 
import 'src/widgets/ButtomTabs.dart';

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: GlobalLayout(title: 'flutter_router_demo'),
    );
  }
}

void main() => runApp(App());
```
```java 
class GlobalLayout extends StatefulWidget {
  @override
  GlobalLayoutState createState() => GlobalLayoutState();
}

class GlobalLayoutState extends State<GlobalLayout> {
    int current = 0;

    void onChangeTab(int n) {
        setState(() {
          current = n;
        });
    }

    return Scaffold(
    //...
        bottomNavigationBar: ButtomTabs(
            current: current,
            onChangeTab: onChangeTab,
        )
    )
}

```

#### ButtomTabs.dart
```java  
import 'package:flutter/material.dart';

class ButtomTabs extends StatelessWidget {
  ButtomTabs({this.current, this.onChangeTab});
  final int current;
  final Function onChangeTab;
  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
        type: BottomNavigationBarType.fixed, //超過3個item要強制設定fixed
        currentIndex: current,
        items: [
          BottomNavigationBarItem(title: Text("Home"), icon: Icon(Icons.home)),
          BottomNavigationBarItem(title: Text("List"), icon: Icon(Icons.list)),
          BottomNavigationBarItem(
              title: Text("Message"), icon: Icon(Icons.message)),
        ],
        onTap: onChangeTab);
  }
}

```

當`BottomNavigationBarItem`數量超過3個的時候，`BottomNavigationBar`的`type`會從預設的`fixed`變成`shifting`，所以假設要放到4個或5個，要手動指定`type:BottomNavigationBarType.fixed`。


---

## Drawer 左邊打開的漢堡選單

![](https://i.imgur.com/x52UmOG.png =40%x) ![](https://i.imgur.com/BaWN0VG.png =40%x)

#### main.dart
```java 
return Scaffold(
    drawer: Drawer(
          child: ListView(
        padding: EdgeInsets.zero,
        children: <Widget>[
          DrawerHeader(
            decoration: BoxDecoration(
              color: Colors.red,
            ),
            child: Text(
              'Drawer Header',
              style: TextStyle(
                color: Colors.white,
                fontSize: 24,
              ),
            ),
          ),
          ListTile(
            leading: Icon(Icons.message),
            title: Text('Messages'),
          ),
          ListTile(leading: Icon(Icons.access_alarms), title: Text('Alert')),
          ListTile(leading: Icon(Icons.device_hub), title: Text('Device')),
        ],
      ))
)
```

### 使用`Listview.build()`

#### main.dart
```java 
return Scaffold(
    drawer: DrawerItems(),
)
```

#### DrawerItems.dart
```java 
import 'package:flutter/material.dart';

class DrawerItems extends StatelessWidget {
  final List<Map<String, dynamic>> menus = [
    {'name': 'Home', 'icon': 59530},
    {'name': 'Account', 'icon': 59705},
    {'name': 'Setting', 'icon': 59576},
  ];
  @override
  Widget build(BuildContext context) {
    return Drawer(
        child: ListView.builder(
            padding: EdgeInsets.zero,
            itemCount: menus.length + 1,
            itemBuilder: (BuildContext context, int i) {
              if (i == 0) {
                return DrawerHeader(
                  decoration: BoxDecoration(
                    color: Colors.red,
                  ),
                  child: Text(
                    'Drawer Header',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 24,
                    ),
                  ),
                );
              }
              return ListTile(
                leading: Icon(IconData(menus[i - 1]["icon"],
                    fontFamily: 'MaterialIcons')),
                title: Text(menus[i - 1]["name"]),
              );
            }));
  }
}

```
- `Drawer`：會從左邊打開一個固定寬度的區域，如果不加上這個，左側選單會變成滿版的。
- `itemCount`：因為最上面要新增一個`DrawerHeader`，所以`itemCount`要+1。
- `return`：`(i == 0)`的時候return `DrawerHeader`，其他時候return 一般的`ListTile`。


### 加入點擊事件

#### main.dart
加入`router`
```java 
import 'src/pages/PageWrap.dart';

return MaterialApp(
    routes: <String, WidgetBuilder>{
        '/account': (BuildContext context) => PageWrap(title: 'Account'),
        '/setting': (BuildContext context) => PageWrap(title: 'Setting'),
      },
)
```

#### DrawerItems.dart
- 選單的資料中，加入`path`資料。
```java 
final List<Map<String, dynamic>> menus = [
    {'name': 'Home', 'icon': 59530},
    {'name': 'Account', 'path': 'account', 'icon': 59705},
    {'name': 'Setting', 'path': 'setting', 'icon': 59576},
  ];
  
```  
- `pushNamed`裡面是要放`/path/name`這種資料，所以字串前面加上一個`/`
```java
return ListTile(
    //...
    onTap: () {
        Navigator.of(context).pushNamed('/${menus[i - 1]["path"]}');
    },
);
```


#### PageWrap.dart
```java 
import 'package:flutter/material.dart';

class PageWrap extends StatelessWidget {
  PageWrap({this.title});
  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Text(title),
      ),
    );
  }
}
```