在螢幕上新增一個 drawer
在 Material Design 設計準則裡,主要提供了兩種導向方式:Tab 和 Drawer。當沒有足夠的空間來支援 tab 導向時,drawer 提供了另一個方便的選擇。
在 Flutter中,我們可以將 Drawer
widget 與 Scaffold
結合使用來建立一個具有 Material Design 風格的 Drawer 佈局。請參見如下的步驟:
-
建立一個
Scaffold
。 -
新增一個 drawer。
-
向 drawer 中新增內容。
-
透過程式碼關閉 drawer。
Scaffold
1. 建立一個 為了嚮應用中新增一個 Drawer,我們需要將其放在 Scaffold
widget 中。
Scaffold Widget 為遵循 Material 設計規則的應用程式提供了一套統一的視覺化結構。它同樣支援一些特殊的 Material Design 元件,例如 Drawer,AppBar 和 SnackBar 等。
在這個例子中,我們想要建立一個帶有 drawer
的 Scaffold
:
Scaffold(
appBar: AppBar(
title: const Text('AppBar without hamburger button'),
),
drawer: // Add a Drawer here in the next step.
);
2. 新增一個 drawer
我們現在可以在 Scaffold
上新增一個 drawer。雖然 drawer 可以是任何 widget,但最好還是使用 Material Library
中的 Drawer
widget,因為這樣才符合 Material Design 設計規範。
Scaffold(
appBar: AppBar(
title: const Text('AppBar with hamburger button'),
),
drawer: Drawer(
child: // Populate the Drawer in the next step.
),
);
3. 向 drawer 中新增內容
既然已經有了一個 Drawer
,我們現在就可以向其中新增內容。在這個例子中,我們將使用 ListView
。雖然你也可以使用 Column
widget,但是 ListView
在這種情況下將是更好的選擇,因為如果內容所佔用的空間超出了螢幕的話,它將能夠允許使用者進行捲動。
我們將使用 DrawerHeader
和兩個 ListTile
widget 填充 ListView
。有關使用 List 的更多訊息,請參閱實用教程中的 list recipes。
Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: const Text('Item 1'),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: const Text('Item 2'),
onTap: () {
// Update the state of the app.
// ...
},
),
],
),
);
4. 透過程式設計關閉 drawer
我們經常需要在使用者點選某個專案後就將 Drawer 關掉。那麼怎樣才能做到這一點呢?請試試看 Navigator
。
當用戶開啟 Drawer 時,Flutter 會將 drawer widget 覆蓋在當前的導向堆疊上。因此,要關閉 drawer,我們可以透過呼叫 Navigator.pop(context)
來實現。
ListTile(
title: const Text('Item 1'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
互動式範例
該範例展示了如何在 Scaffold
中使用 Drawer
。
Drawer
中包含三個 ListTile
。
_onItemTapped
方法會改變當前選中的元素,並在 Scaffold
中央展示對應的文字。
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const appTitle = 'Drawer Demo';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Center(
child: _widgetOptions[_selectedIndex],
),
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: [
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);
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: const Text('Business'),
selected: _selectedIndex == 1,
onTap: () {
// Update the state of the app
_onItemTapped(1);
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: const Text('School'),
selected: _selectedIndex == 2,
onTap: () {
// Update the state of the app
_onItemTapped(2);
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
);
}
}