前言:工作中最简单的一个APP也要具备一个功能,就是底部导航栏,你很难找出没有底部导航栏的应用。
实现的效果:
编写过程如下:
1、主入口文件main.dart的编写
首先我们先写一个主入口文件,这个文件只是简单的APP通用结构,最主要的是要引入自定义的BottomNavigationWidget
组件。
import 'package:flutter/material.dart';
import 'bottom_navigation_widget.dart';
void main()=> runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title:'Flutter bottomNavigationBar',
theme:ThemeData.light(),
home:BottomNavigationWidget()
);
}.
}
2、StatefulWidget 讲解
在编写BottomNaivgationWidget
组件前,我们需要简单了解一下什么是StatefulWidget
.
StatefulWidget
具有可变状态(state)的窗口组件(widget)。使用这个要根据变化状态,调整State值。
在lib目录下,新建一个bottom_navigation_widget.dart
文件。
它的初始化和以前使用的StatelessWidget
不同,我们在VSCode中直接使用快捷方式生成代码(直接在VSCode中输入stful):
class name extends StatefulWidget {
_nameState createState() => _nameState();
}
class _nameState extends State<name> {
@override
Widget build(BuildContext context) {
return Container(
child: child,
);
}
}
上面的代码可以清楚的看到,使用StatefulWidget
分为两个部分,第一个部分是继承与StatefullWidget
,第二个部分是继承于State
.其实State
部分才是我们的重点,主要的代码都会写在State
中。
3、BottomNaivgationWidget自定义
接下来我们就要创建BottomNaivgationWidget
这个Widget了(将上边name换成BottomNaivgationWidget
),只是建立一个底部导航。
import 'package:flutter/material.dart';
class BottomNavigationWidget extends StatefulWidget {
_BottomNavigationWidgetState createState() => _BottomNavigationWidgetState();
}
class _BottomNavigationWidgetState extends State<BottomNavigationWidget> {
final _BottomNavigationColor = Colors.blue;
@override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon:Icon(
Icons.home,
color:_BottomNavigationColor,
),
title:Text(
'Home',
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)
)
),
BottomNavigationBarItem(
icon:Icon(
Icons.airplay,
color:_BottomNavigationColor,
),
title:Text(
'AipPlay',
style:TextStyle(color:_BottomNavigationColor)
)
),
],
type:BottomNavigationBarType.fixed
),
);
}
}
4、子页面的编写
子页面我们就采用最简单的编写了,只放入一个AppBar(去除背景,保留标题)
和一个本地图片。
先来写一个HomeScreen组件,新建一个pages目录,然后在目录下面新建home_screen.dart
文件。
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
decoration:BoxDecoration( //添加decoration修饰
image: DecorationImage(
image: AssetImage('images/img2.jpg'),//添加本地图片
fit: BoxFit.cover
)
),
child: Scaffold(
//把scaffold的背景色改成透明
backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text('Home'),
elevation: 0.0,//去除appbar的阴影
backgroundColor: Colors.transparent//把appbar的背景色改成透明
),
),
);
}
}
分别建立:
- email_screen.dart
- pages_screen.dart
- airplay_screen.dart
这些都是导航要用的子页面,有了这些页面,我们才能继续编写代码。
5、重写initState()方法
我们要在bottom_navigation_widget.dart文件中重新initState()
方法,把刚才做好的页面进行初始化到一个Widget数组中。有了数组就可以根据数组的索引来切换不同的页面了。这是现在几乎所有的APP采用的方式。
代码如下:
List<Widget> list = List();
@override
void initState(){
list
..add(HomeScreen())
..add(EmailScreen())
..add(PagesScreen())
..add(AirplayScreen());
super.initState();
}
这里的..add()
是Dart语言的..语法,如果你学过编程模式,你一定听说过建造者模式,简单来说就是返回调用者本身。这里list后用了..add(),还会返回list,然后就一直使用..语法,能一直想list里增加widget元素。 最后我们调用了一些父类的initState()
方法。
6、BottomNavigationBar里的响应事件
BottomNavigationBar 常见的属性:
- items :List底部导航条按钮集合
- iconSize :icon
- currentIndex :默认选中第几个
- onTap:选中变化回调函数
-
fixedColor :选中的颜色
- type :BottomNavigationBarType.fixed & BottomNavigationBarType.shifting
BottomNavigationBar
组件里提供了一个相应事件onTap
,这个事件自带一个索引值index
,通过索引值我们就可以和我们list里的索引值相对应了。在bottom_navigation_widget.dart文件添加代码如下:
//默认选中第几个
currentIndex: _currentIndex,
onTap:(int index){
setState((){
_currentIndex= index;
});
},
7、bottom_navigation_widget.dart文件全部代码如下:
import 'package:flutter/material.dart';
import 'pages/home_screen.dart';
import 'pages/pages_screen.dart';
import 'pages/email_screen.dart';
import 'pages/ariplay_screen.dart';
//创建BottomNaivgationWidget这个Widget了,只是建立一个底部导航。
//StatefulWidget具有可变状态(state)的窗口组件(widget)。使用这个要根据变化状态,调整State值。
class ButtomNavigationWidget extends StatefulWidget {
_ButtomNavigationWidgetState createState() => _ButtomNavigationWidgetState();
}
class _ButtomNavigationWidgetState extends State<ButtomNavigationWidget> {
int _currentIndex=0;//初始化索引
List<Widget> list=List(); //定义一个列表用于存放四个widget界面
//初始化State
@override
void initState(){
//向列表中添加widget
list
..add(HomeScreen())
..add(EmailScreen())
..add(PagesScreen())
..add(AriplayScreen());
super.initState();//无名无参,需要调用父类方法
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: list[_currentIndex],//通过索引值设置widget
//创建一个底部导航栏
bottomNavigationBar: BottomNavigationBar(
items: [ //按钮的数组,所以要是用index索引
BottomNavigationBarItem( //底部导航栏子按钮及属性设置
icon:Icon(
Icons.home,
color: Colors.blue,
),
title:Text('home',style: TextStyle(color: Colors.blue),)
),
BottomNavigationBarItem(
icon:Icon(
Icons.email,
color: Colors.blue,
),
title:Text('email',style: TextStyle(color: Colors.blue),)
),
BottomNavigationBarItem(
icon:Icon(
Icons.pages,
color: Colors.blue,
),
title:Text('pages',style: TextStyle(color: Colors.blue),)
),
BottomNavigationBarItem(
icon:Icon(
Icons.airplay,
color: Colors.blue,
),
title:Text('airplay',style: TextStyle(color: Colors.blue),)
),
],
//默认选中第几个
currentIndex: _currentIndex,//哪个按钮被选中,_currentIndex就被赋值为多少
//底部按钮的点击事件,这个事件自带一个索引值index,通过索引值就可以和list里的索引值相对应了
onTap: (int index){
setState(() { //更新点击按钮后的状态
_currentIndex=index;
});
},
),
);
}
}