Flutter学习笔记(三)整体布局:bottomNavigationBar,AppBar,Drawer的使用

it2022-05-10  55

Flutter学习笔记(三)整体布局:bottomNavigationBar,AppBar,Drawer的使用

bottonNavigationbar的使用AppBar的Leading的自定义Drawer的自定义DrawerHeader

在写完大概的登陆注册页面之后,就来到整体的布局了,这个应用的功能主要是为了让用户更好的完成小组任务,用户分为两种:组长和组员。组长可以分配并管理任务,等等区别以后再说,现在先来看看整体的布局。

bottonNavigationbar的使用

先看效果图: 整体布局使用的就是一个bottomNavigationBar,分别有Home,Group,News三个部分,上面是一个AppBar,在Group页面中的AppBar中新增一个bottom属性:TabBar,并且包含Owned Group,Joined Group,Passed Group三个tab,然后来看代码:

//声明需要的变量 int _currentIndex = 0; BottomNavigationBarType _type = BottomNavigationBarType.shifting; List<NavigationIconView> _navigationViews; List<Widget> list = List(); List<String> tilTes = ["Home","Group","News"]; TabController _tabController; //需要定义一个Controller List<String> tabs = ["Owned Group", "Joined Group","Passed Group"]; @override void initState(){ super.initState(); //新增三个页面,建议放在不同的dart文件中。 list ..add(HomeScreen()) ..add(GroupScreen()) ..add(NewsScreen()); //新增底部的三个选项 _navigationViews = <NavigationIconView>[ NavigationIconView( icon: const Icon(Icons.home,color: Colors.blue), title: 'Home', vsync: this, ), NavigationIconView( icon: const Icon(Icons.group_work,color: Colors.blue), title: 'Group', vsync: this, ), NavigationIconView( icon: const Icon(Icons.message,color: Colors.blue), title: 'News', vsync: this, ), ]; _navigationViews[_currentIndex].controller.value = 1.0; _tabController = TabController(length: tabs.length, vsync:this); }

然后是构造页面的代码:

Widget build(BuildContext context) { userEmail=ModalRoute.of(context).settings.arguments; //print(userEmail); final BottomNavigationBar botNavBar = BottomNavigationBar( items: _navigationViews .map<BottomNavigationBarItem>((NavigationIconView navigationView) => navigationView.item) .toList(), currentIndex: _currentIndex, fixedColor: Colors.blue, type: _type, onTap: (int index) { setState(() { _currentIndex = index; }); }, ); //如果是Group页面 if(_currentIndex==1) { return Scaffold( appBar: AppBar( leading: new Container( margin: EdgeInsets.only(top: 3, left: 3,right: 3,bottom: 3),//容器补白 decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( image: new ExactAssetImage('assets/images/user.png'), fit: BoxFit.cover ), ), ), centerTitle: true, title: Text("Group"), bottom: TabBar( controller: _tabController, tabs: tabs.map((e) => Tab(text: e)).toList() ), actions: <Widget>[ //导航栏右侧按钮 IconButton(icon: Icon(Icons.mail_outline), onPressed: () { }), ], ), body:TabBarView( controller: _tabController, //创建3个Tab页 children: tabs.map((e) { return Container( child: GroupScreen(), ); }).toList(), ) , bottomNavigationBar: botNavBar, drawer: UserDrawerPage(userEmail), ); } //其他情况 return Scaffold( appBar: new AppBar( leading: new Container( margin: EdgeInsets.only(top: 3, left: 3,right: 3,bottom: 3),//容器补白 decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( image: new ExactAssetImage('assets/images/user.png'), fit: BoxFit.cover ), ), ), centerTitle: true, title: Text(tilTes[_currentIndex]), actions: <Widget>[ new IconButton( icon: new Icon(Icons.mail_outline), onPressed: () { }) ], ), body: list[_currentIndex], bottomNavigationBar: botNavBar, drawer: UserDrawerPage(userEmail), ); }

这一段有一个小问题,也就是在我为什么要将group单独拿出来呢?明明可以在新增的三个页面中新建手脚架Scaffold然后在里面分别制作三个AppBar,我之前是这样做的,但是这样有一个问题,那就是在group的子页面打开侧边drawer的时候,无法覆盖底部的bottomNavigationBar,而上边的滑动栏必须是和AppBar一起声明的,作为其bottom属性的TapBar,所以必须要让这整个页面是在同一个AppBar当中。于是想了这个笨方法来实现。

AppBar的Leading的自定义

从上述代码中可以发现,AppBar的leading是可以自定义的,我放了一张头像,按照精神模型,用户一定会通过点击这个头像来打开侧边栏Drawer,但是很遗憾,声明为自定义图片的时候没有办法触发点击的事件。这一点让我疑惑了很久,因为我发现在wan_android的源码中,没有对这个Container做特殊的处理,却可以触发打开Drawer的事件。后来查阅的资料发现,只要通过修改dart的源码,就可以简答实现这个功能,这一部分内容详情请看Flutter 之 AppBar 这样的骚操作你知道吗?这个里面讲解的十分详细。

Drawer的自定义DrawerHeader

先看侧边栏的效果图: flutter本身有一个UserAccountsDrawerHeader可以使用,但是样式很固定,所以大多数采用的是自定义的DrawerHeader,布局采用了一个Stack来放置头像图片和文本,然后通过BoxDecoration来自定义背景图片,当然如果不使用image来设置背景图片的话,还可以使用gradient:来制作一个渐变的背景色的效果。整个drawer是一个ListView,包含自定义的DrawerHeader和下面的菜单选项。 代码如下:

import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'login_page.dart'; class UserDrawerPage extends StatefulWidget{ UserDrawerPage(this.userEmail); final String userEmail; @override _UserPageState createState()=>_UserPageState(userEmail); } class _UserPageState extends State<UserDrawerPage>{ _UserPageState(this.userEmail); final String userEmail; String userName="New user"; @override Widget build(BuildContext context) { //print(userEmail); Widget selfHeader = new DrawerHeader( child: new Stack( children: <Widget>[ new Align( alignment: FractionalOffset.bottomLeft, child: Container( height: 140.0, margin: EdgeInsets.only(left: 15.0, bottom: 0), child: new Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ new CircleAvatar( backgroundImage: AssetImage('assets/images/user.png'), radius: 35.0, ), new Padding( padding: EdgeInsets.symmetric(horizontal: 22.0), child: SizedBox(height: 10), ), new Container( margin: EdgeInsets.only(left:5.0), child: new Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Text(userName, style: new TextStyle( fontSize: 18.0, fontWeight: FontWeight.w400, color: Colors.white),), new SizedBox(height: 4), new Text(userEmail, style: new TextStyle( fontSize: 14.0, color: Colors.white),), ], ), ), ],), ), ) ], ), padding: EdgeInsets.zero, decoration: new BoxDecoration( // gradient: LinearGradient( // colors: [Colors.blue, Colors.indigo], // begin: FractionalOffset(1, 1), // end: FractionalOffset(0, 0) // ), image: new DecorationImage( image: AssetImage("assets/images/userbg.png"), fit: BoxFit.fitHeight, ) ), ); return new Drawer( child: ListView( padding: EdgeInsets.zero, children: <Widget>[ //在这里使用自定义的header selfHeader, ListTile(title: Text('Homepage'), leading: new CircleAvatar( child: new Icon(Icons.home), backgroundColor: Colors.blue, foregroundColor: Colors.white, radius: 18, ), onTap: () { Navigator.pop(context); }, ), ListTile(title: Text('Partners'), leading: new CircleAvatar( child: new Icon(Icons.people), backgroundColor: Colors.blue, foregroundColor: Colors.white, radius: 18, ), onTap: () { Navigator.pop(context); }, ), ListTile(title: Text('History'), leading: new CircleAvatar( child: new Icon(Icons.history), backgroundColor: Colors.blue, foregroundColor: Colors.white, radius: 18, ), onTap: () { Navigator.pop(context); }, ), ListTile(title: Text('Stars'), leading: new CircleAvatar( child: new Icon(Icons.star), backgroundColor: Colors.blue, foregroundColor: Colors.white, radius: 18, ), onTap: () { Navigator.pop(context); }, ), ListTile(title: Text('Schedule'), leading: new CircleAvatar( child: new Icon(Icons.schedule), backgroundColor: Colors.blue, foregroundColor: Colors.white, radius: 18, ), onTap: () { Navigator.pop(context); }, ), ListTile(title: Text('Switch'), leading: new CircleAvatar( child: new Icon(Icons.cached), backgroundColor: Colors.deepOrange, foregroundColor: Colors.white, radius: 18, ), onTap: () { _showSwitchDialog(context); }, ), ], ), ); } }

参考资料:

Flutter - Drawer 抽屉视图与自定义headerFlutter 之 AppBar 这样的骚操作你知道吗?Flutter Decoration背景设定Flutter基础—定位对齐之对齐

最新回复(0)