一个完整的路由页可能会包含导航栏、抽屉菜单(Drawer)以及底部Tab导航菜单等。
Scaffold是一个路由页的骨架,我们使用它可以很容易地拼装出一个完整的页面。
实现以下界面
一个导航栏
导航栏右边有一个分享按钮
有一个底部导航
右下角有一个悬浮的动作按钮
代码如下:
import 'package:flutter/material.dart';
class StudyScaffold extends StatefulWidget{
@override
State createState() {
return StudyScaffoldState();
}
}
class StudyScaffoldState extends State{
int selectIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(//导航栏
title: Text("Scaffold页面"),
actions: [
IconButton(
icon: Icon(Icons.share),
onPressed: (){
print("啦啦啦");
},
),
],
),
bottomNavigationBar: BottomNavigationBar(//底部导航
items: [
BottomNavigationBarItem(icon: Icon(Icons.home),title: Text("首页")),
BottomNavigationBarItem(icon: Icon(Icons.account_box),title: Text("通讯录")),
BottomNavigationBarItem(icon: Icon(Icons.add_alert),title: Text("消息")),
BottomNavigationBarItem(icon: Icon(Icons.person),title: Text("我的")),
],
currentIndex: selectIndex,//选中位置
fixedColor:Colors.blue,//选中状态颜色
type: BottomNavigationBarType.fixed,//解决底部导航按钮超过3个后滑动问题
onTap: onItemTap,//
),
floatingActionButton: FloatingActionButton(//悬浮按钮
child: Icon(Icons.add),
onPressed: (){
print("add");
},
),
);
}
void onItemTap(int index) {
setState(() {
selectIndex = index;
});
}
}
Scaffold的drawer和endDrawer属性可以分别接受一个Widget来作为页面的左、右抽屉菜单。如果开发者提供了抽屉菜单,那么当用户手指从屏幕左(或右)侧向里滑动时便可打开抽屉菜单。
添加一个左侧抽屉菜单
//抽屉
class MyDrawer extends StatelessWidget{
const MyDrawer({Key? key,}):super(key: key);
@override
Widget build(BuildContext context) {
return Drawer(
child: MediaQuery.removePadding(
context: context,
removeTop: true,//移除抽屉菜单顶部默认留白
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 50),
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: ClipOval(
child: Image.asset("images/tree.jpg",width: 80,height:80,fit: BoxFit.cover,),
),
),
Text(
"行云流水",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
],
),
),
Expanded(
child: ListView(
children: [
ListTile(
leading: Icon(Icons.add),
title: Text("添加设备"),
),
ListTile(
leading: Icon(Icons.settings),
title: Text("管理设备"),
),
],
)
),
],
),
),
);
}
}
scaffold中添加 drawer: MyDrawer(),
如果给Scaffold添加了抽屉菜单,默认情况下Scaffold会自动将AppBar的leading设置为菜单按钮,点击它便可打开抽屉菜单。
如图:
抽屉菜单通常将Drawer组件作为根节点,它实现了Material风格的菜单面板,MediaQuery.removePadding可以移除Drawer默认的一些留白。
AppBar是一个Material风格的导航栏,通过它可以设置导航栏标题、导航栏菜单、导航栏底部的Tab标题等
AppBar({
Key key,
this.leading, //导航栏最左侧Widget,常见为抽屉菜单按钮或返回按钮。
this.automaticallyImplyLeading = true, //如果leading为null,是否自动实现默认的leading按钮
this.title,// 页面标题
this.actions, // 导航栏右侧菜单
this.bottom, // 导航栏底部菜单,通常为Tab按钮组
this.elevation = 4.0, // 导航栏阴影
this.centerTitle, //标题是否居中
this.backgroundColor,
})
自定义菜单图标
leading: Builder(
builder: (context){
return IconButton(
onPressed: (){
Scaffold.of(context).openDrawer();
},
icon: Icon(Icons.dashboard,color: Colors.white,)
);
},
),
class StudyScaffoldState extends State with SingleTickerProviderStateMixin{
int selectIndex = 0;
List tabValues = ["科技","军事","历史"];
late TabController tabController ;
@override
void initState() {
创建Controller
tabController = TabController(length: tabValues.length, vsync: this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(//导航栏
title: Text("Scaffold页面"),
actions: [
IconButton(
icon: Icon(Icons.share),
onPressed: (){
print("啦啦啦");
},
),
],
leading: Builder(
builder: (context){
return IconButton(
onPressed: (){
Scaffold.of(context).openDrawer();
},
icon: Icon(Icons.dashboard,color: Colors.white,)
);
},
),
bottom: TabBar(
controller: tabController,
tabs: tabValues.map((e) => Tab(text: e,)).toList(),
indicatorColor: Colors.red,//指示器的颜色
indicatorSize:TabBarIndicatorSize.tab,//指示器的宽度 .label 宽度和字体宽度一样 .tab 宽度为整个tab的宽度
isScrollable: false,//是否可滑动 当tab数量特别多的时候设为true
labelColor:Colors.purple,//选中的颜色
unselectedLabelColor: Colors.white,//未选中的颜色
indicatorWeight: 3,//指示器的高度
),
),
body: TabBarView(
controller: tabController,
children: tabValues.map((e){
return Container(
alignment: Alignment.center,
child: Text(e,textScaleFactor: 2,),
);
}).toList(),
),
bottomNavigationBar: BottomNavigationBar(//底部导航
items: [
BottomNavigationBarItem(icon: Icon(Icons.home),title: Text("首页")),
BottomNavigationBarItem(icon: Icon(Icons.account_box),title: Text("通讯录")),
BottomNavigationBarItem(icon: Icon(Icons.add_alert),title: Text("消息")),
BottomNavigationBarItem(icon: Icon(Icons.person),title: Text("我的")),
],
currentIndex: selectIndex,//选中位置
fixedColor:Colors.blue,//选中状态颜色
type: BottomNavigationBarType.fixed,//解决底部导航按钮超过3个后滑动问题
onTap: onItemTap,//
),
floatingActionButton: FloatingActionButton(//悬浮按钮
child: Icon(Icons.add),
onPressed: (){
print("add");
},
),
);
}
void onItemTap(int index) {
setState(() {
selectIndex = index;
});
}
}
TabBarView配合TabBar实现了同步切换和滑动状态同步。
效果
FloatingActionButton是Material设计规范中的一种特殊Button,通常悬浮在页面的某一个位置作为某种常用动作的快捷入口。
通过Material组件库提供的BottomNavigationBar和BottomNavigationBarItem两种组件来实现Material风格的底部导航栏。
Material组件库中提供了一个BottomAppBar 组件,它可以和FloatingActionButton配合实现这种“打洞”效果。
bottomNavigationBar: BottomAppBar(
color: Colors.white,
shape: CircularNotchedRectangle(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,//均分
children: [
IconButton(
onPressed: (){
},
icon: Icon(Icons.home),
),
IconButton(
onPressed: (){
},
icon: Icon(Icons.account_box)
),
SizedBox(),
IconButton(
onPressed: (){
},
icon: Icon(Icons.add_alert)
),
IconButton(
onPressed: (){
},
icon: Icon(Icons.person)
),
],
),
),
floatingActionButton: FloatingActionButton(//悬浮按钮
child: Icon(Icons.add),
onPressed: (){
print("add");
},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,