这是转载自简书星星编程的一篇博文,感谢分享。
本文通过一个案例,展示了Flutter通过bottomNavigationBar和DefaultTabController组件实现底部tab栏和顶部tab栏的实现:
下图是最终效果:
可以看到,顶部有搜索框和tabbar,使用了自定义AppBar配合DefaultTabController实现,底部为常见的
bottomNavigationBar tab栏。
一、通过bottomNavigationBar实现底部:
重新build方法会返回一个Scaffold组件,在这个组件下面添加底部导航属性bottomNavigationBar,onTap事件实现点击底部导航栏页面之间的切换和状态改变。因为界面有变化,所以这里使用的是动态组件StatefulWidget。
02 | Widget build(BuildContext context) { |
04 | backgroundColor: Color.fromRGBO(244, 245, 245, 1.0), |
05 | bottomNavigationBar: BottomNavigationBar( |
06 | type:BottomNavigationBarType.fixed, |
07 | currentIndex: currentIndex, |
12 | currentPage = _tabs[currentIndex]; |
15 | fixedColor: Colors.green, |
_bottomTabs是定义的底部Tabbar的List<BottomNavigationBarItem>,包含了Tabbar的每个item。item有默认icon和选择的activeIcon,这里使用的都是加载的本地图片,加载本地图片需要以下配置。
1、以当前Demo为例,建立一个assets文件夹images,下面建2.0x和3.0x两个文件夹,用来放2倍图和3倍图,另外直接在images文件夹下放一倍图。
2、需要在pubspec.yaml文件中声明每张图片。
3、Tabbar每个item的icon和activeIcon加载本地图。
01 | final List<BottomNavigationBarItem> _bottomTabs = [ |
02 | BottomNavigationBarItem( |
03 | icon:Image.asset( "images/ic_tab_home_normal.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
04 | activeIcon:Image.asset( "images/ic_tab_home_active.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
07 | BottomNavigationBarItem( |
08 | icon:Image.asset( "images/ic_tab_subject_normal.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
09 | activeIcon:Image.asset( "images/ic_tab_subject_active.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
12 | BottomNavigationBarItem( |
13 | icon:Image.asset( "images/ic_tab_group_normal.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
14 | activeIcon:Image.asset( "images/ic_tab_group_active.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
17 | BottomNavigationBarItem( |
18 | icon:Image.asset( "images/ic_tab_shiji_normal.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
19 | activeIcon:Image.asset( "images/ic_tab_shiji_active.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
22 | BottomNavigationBarItem( |
23 | icon:Image.asset( "images/ic_tab_profile_normal.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
24 | activeIcon: Image.asset( "images/ic_tab_profile_active.png" ,fit: BoxFit.cover,width: 40,height: 40,), |
_tabs是Tabbar所有页面的集合:
在initState初始化currentPage,显示首页:
4 | currentPage=_tabs[currentIndex]; |
切换Tabbar实现onTap刷新状态并更改currentPage渲染页面。
二、顶部Tabbar
顶部Tabbar相对于底部Tabbar简单一些,顶部Tabbar切换时不需要手动改变状态,所以这里使用StatelessWidget。顶部Tabbar使用
DefaultTabController组件,声明切换item的个数length属性,并保证与tabs和TabBarView的个数一致,否则会报错。
AppBar组件下的Title也是一个组件,这里添加一个自定义的搜索组件SearchTextFieldWidget,这里就不过多介绍了。
02 | Widget build(BuildContext context) { |
03 | return DefaultTabController( |
07 | title: SearchTextFieldWidget( |
08 | hintText: "用一部电影来形容你的2019" , |
09 | onSubmitted: (searchContent) { |
13 | backgroundColor: Colors.green, |
15 | indicatorColor: Colors.white, |
39 | children: <Widget>[Home(), Home(), Home(), Home(), Home(), Home()], |