Scaffold
可以設定 drawer
與 endDrawer
特性,一般是用來做左、右側欄時使用,通常會搭配 Drawer
使用。例如:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Openhome.cc'),
),
drawer: Drawer(),
)
)
);
就這麼簡單,要先認識的並不是 Drawer
,而是 Scaffold
本身提供的側欄行為,以設定了 drawer
來說,預設情況下,你可以從螢幕左側往中拉,如果 Scaffold
有設定 AppBar
,也可以按下 leading
處的按鈕,兩個方式都會顯示側欄,按側欄範圍外的任意位置,就可以收起側欄。
drawer
與 endDrawer
接受的都是 Widget
型態,也就是說,就算不使用 Drawer
,任何 Widget
基本上都可以有這個行為,這表示你的側欄有很高的自訂性;當然,Drawer
有一些基本設定是蠻方便的,例如可自行判斷螢幕空間,決定自身大小之類的,沒特別的需求下,使用它還是蠻方便的。
Scaffold
有幾個與側欄相關的特性,方才談到可以用拖曳來打開側欄,Scaffold
的 drawerDragStartBehavior
可以決定手勢操作何時被視為拖曳行為,預設值是 DragStartBehavior.start
,也就是螢幕邊偵測到手勢操作就視為拖曳開始,設為 DragStartBehavior.down
的話,就是在 down 事件時才視為拖曳開始,這影響的主要應該是動畫的時機之類的吧!
drawerEdgeDragWidth
預設是 20 像素,用來設定螢幕邊手勢操作引發側欄的範圍;drawerScrimColor
可以設定側欄未涵蓋區域的顏色,預設是 Colors.black54
。
(在撰寫這段文字的同時,API 文件上有個 drawerEnableOpenDragGesture
,可用來停用拖曳操作側欄,不過我寫文件時,是固定在 flutter_windows_v1.12.13+hotfix.9-stable.zip 這個版本,drawerEnableOpenDragGesture
應該是後續版本中提供的,從 PR 來看,時間點是 2020 年 2 月 20 日後加入的。)
知道 Scaffold
的側欄基本行為後,接著就看你怎麼設計側欄了,常見的是使用 Drawer
搭配 ListView
、DrawerHeader
等來設計。例如:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Home()
)
);
class Home extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Home();
}
class _Home extends State<Home> {
final books = [
Book(
imgSrc: 'https://openhome.cc/Gossip/images/ACL059300.jpg',
name: 'Java SE 14 技術手冊',
),
Book(
imgSrc: 'https://openhome.cc/Gossip/images/ACL054400.jpg',
name: 'Python 3.7 技術手冊',
),
Book(
imgSrc: 'https://openhome.cc/Gossip/images/AEL022800.jpg',
name: 'JavaScript 技術手冊',
)
];
final titles = ['Java', 'Python', 'JavaScript'];
var bookIdx;
@override
void initState() {
bookIdx = 0;
super.initState();
}
void page(idx) {
setState(() {
bookIdx = idx;
});
}
@override
Widget build(BuildContext context) {
final children = List<Widget>();
children.add(DrawerHeader(
child: Text(
'著作',
style: TextStyle(
color: Colors.white
),
),
decoration: BoxDecoration(
color: Colors.blue,
),
));
for(var i = 0; i < titles.length; i++) {
children.add(ListTile(
title: Text(titles[i]),
onTap: () {
page(i);
// 彈出路由
Navigator.pop(context);
}
));
}
return Scaffold(
appBar: AppBar(
title: Text('Openhome.cc'),
),
body: books[bookIdx],
drawer: Drawer(
child: ListView(
children: children,
)
),
);
}
}
class Book extends StatelessWidget {
final String imgSrc;
final String name;
Book({this.imgSrc, this.name});
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.network(imgSrc),
),
Text(name)
],
);
}
}
程式碼看來很長,其實只是在組合 UI 罷了,最重要的地方在於,Scaffold
使用路由堆疊來管理側欄,因此在點選側欄中的項目時,透過 Navigator.pop(context)
之類的操作彈出路由,這時側欄就會退出,來看一下操作效果: