实现一个底部导航栏,包含3到4个功能标签,点击对应的导航标签可以切换到对应的页面内容,并且页面抬头显示的内容也会跟着改变。
实际上由于手机屏幕大小的限制,底部导航栏的功能标签一般在3到5个左右,如果太多,会比较拥挤,影响用户体验,实际上目前市面上大多数APP的底部导航标签都控制在4到5个左右。既美观、又不会让用户觉得功能繁杂。这个功能的实现需要用到flutter里的BottonNavigationBar这个控件。
实际上由于手机屏幕大小的限制,底部导航栏的功能标签一般在3到5个左右,如果太多,会比较拥挤,影响用户体验,实际上目前市面上大多数APP的底部导航标签都控制在4到5个左右。既美观、又不会让用户觉得功能繁杂。这个功能的实现需要用到flutter里的BottonNavigationBar这个控件。
属性名 | 类型 | 说明 |
currentIndex | int | 当前索引,用来切换按钮控制 |
fixedColor | Color | 选中按钮的颜色,如果没有指定值,则用系统主题色 |
iconSize | double | 按钮图标大小 |
items | List<BottomNavigationBarItem> | 底部导航条按钮集。每一项是一个BottomNavigationBarItem,有icon图标及title属性 |
onTap | ValueChanged<int> | 按下其中某一个按钮回调事件,需要根据返回的索引设置当前索引 |
首先我们新建一个底部导航控件,由于点击导航标签的时候页面内容是会发生改变的,所以这是一个有状态的控件。
import 'package:flutter/material.dart'; import './home.dart'; import './contacts.dart'; import './me.dart'; // 应用页面使用有状态Widget class App extends StatefulWidget { @override AppState createState() => AppState(); } //应用页面状态实现类 class AppState extends State<App> { //当前选中页面索引 var _currentIndex = 0; //聊天页面 HomePage home; //好友页面 Contacts contacts; //我的页面 Personal me; //根据当前索引返回不同的页面 currentPage(){ switch(_currentIndex) { case 0: //返回聊天页面 if(home == null) { home = new HomePage(); } return home; case 1: //返回好友页面 if(contacts == null) { contacts = new Contacts(); } return contacts; case 2: //返回我的页面 if(me == null) { me = new Personal(); } return me; } } @override Widget build(BuildContext context) { return Scaffold( //底部导航按钮 bottomNavigationBar: new BottomNavigationBar( //通过fixedColor设置选中item的颜色 fixedColor:Colors.red, type: BottomNavigationBarType.fixed, //当前页面索引 currentIndex: _currentIndex, //按下后设置当前页面索引 onTap: ((index){ setState(() { _currentIndex = index; }); }), //底部导航按钮项 items: [ //导航按钮项传入文本及图标 new BottomNavigationBarItem( title: new Text( '聊天', style: TextStyle( color: _currentIndex == 0 ? Color(0xFFF54343) : Color(0xff999999) //0x 后面开始 两位FF表示透明度16进制 后面是颜色 ), ), //判断当然索引做图片切换显示 icon: _currentIndex == 0 ? Image.asset( 'images/nav-icon-index.active.png', 32.0, height: 32.0, ) : Image.asset( 'images/nav-icon-index.png', 32.0, height: 32.0, ) ), new BottomNavigationBarItem( title: new Text( '好友', style: TextStyle( color: _currentIndex == 1 ? Color(0xFFF54343) : Color(0xff999999) ), ), //判断当然索引做图片切换显示 icon: _currentIndex == 1 ? Image.asset( 'images/nav-icon-cat.active.png', 32.0, height: 32.0, ) : Image.asset( 'images/nav-icon-cat.png', 32.0, height: 32.0, ) ), new BottomNavigationBarItem( title: new Text( '我的', style: TextStyle( color: _currentIndex == 2 ? Color(0xFFF54343) : Color(0xff999999) ), ), //判断当然索引做图片切换显示 icon: _currentIndex == 2 ? Image.asset( 'images/nav-icon-user.active.png', 32.0, height: 32.0, ) : Image.asset( 'images/nav-icon-user.png', 32.0, height: 32.0, ) ), ], ), //中间显示当前页面 body: currentPage(), ); } }
fixedColor设置选中的颜色,下面可以不单独写color。
新建三个dart文件,分别用于新建3个主体展示页面,这三个页面都是带一个appbar和body,appbar用于显示对应的导航标签,body里显示标签大图标。三个文件的写法基本是一致的。
import 'package:flutter/material.dart'; class Personal extends StatefulWidget{ @override State<StatefulWidget> createState() { return new PersonalState(); } } class PersonalState extends State<Personal>{ @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('我的'), ), body: new Center( child: Icon(Icons.mood,size: 130.0,color: Colors.blue,), ), ); } }
另外一种实现方法,重新initState()
方法:
List<Widget> blist = List(); @override void initState(){ blist ..add(HomePage()) ..add(Contacts()) ..add(Personal()); super.initState(); }
这里的..add()
是Dart语言的..语法,如果你学过编程模式,你一定听说过建造者模式,简单来说就是返回调用者本身。这里list后用了..add(),还会返回list,然后就一直使用..语法,能一直想list里增加widget元素。 最后我们调用了一些父类的initState()
方法。
完整代码:
import 'package:flutter/material.dart'; import './home.dart'; import './contacts.dart'; import './me.dart'; class MyApp extends StatefulWidget { @override MyAppState createState() => MyAppState(); } class MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('底部导航示例')), body: BottomNavigationWidget(), ); } } class BottomNavigationWidget extends StatefulWidget { _BottomNavigationWidgetState createState() => _BottomNavigationWidgetState(); } class _BottomNavigationWidgetState extends State<BottomNavigationWidget> { final _BottomNavigationColor = Colors.red; int _currentIndex = 0; List<Widget> blist = List(); @override void initState(){ blist ..add(HomePage()) //建造者模式,简单来说就是返回调用者本身。这里blist后用了..add(),还会返回blist ..add(Contacts()) ..add(Personal()); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar:BottomNavigationBar( items: [ BottomNavigationBarItem( icon: Icon(Icons.home,color: _BottomNavigationColor,), title:Text('Hmoe',style: TextStyle(color: _BottomNavigationColor),) ), BottomNavigationBarItem( icon: Icon(Icons.email,color: _BottomNavigationColor,), title:Text('Email',style: TextStyle(color: _BottomNavigationColor),) ), BottomNavigationBarItem( icon: Icon(Icons.pages,color: _BottomNavigationColor,), title:Text('Pages',style: TextStyle(color: _BottomNavigationColor),) ), ], currentIndex: _currentIndex, //当前页面索引,高亮 onTap: (int index){ setState(() { _currentIndex = index; }); }, ) , body: blist[_currentIndex], ); } }