实现
成员变量
List<Widget> pages = List<Widget>();用来存放tabs分别对应的页面。
tabbar作为内容的容器 CustomerNotification用来容器内部Widget来通知tabbar做出改变。
NotificationListener的’ child‘是页面显示内容,NotificationListener用来监听CustomerNotification。
看设计,TabBar是悬浮的设计,不能用官方库提供的TabBar。TabBar和后面的内容是堆叠的,所以用Stack widget。
Stack: 取代线性布局,Stack允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于Stack的上下左右四条边的位置。Stacks是基于Web开发中的绝对定位(absolute positioning )布局模型设计的。
Positioned,用Positioned绝对定位悬浮的TabBar。 bottom: 15, left: 20, right: 20(top这里不需要设置)分别设计和容器的边距。
Positioned的child就是你自己需要定制的tabbar形状。
全部代码如下:
/*
* File: /Users/ottpay/Git/fyh_transfer/lib/Account/accountHomePage.dart
* Created Date: 2019-09-27 4:13:15
* Author: 木穆 pengxuan.li@ott.ca
* Copyright (c) 2019 OTT Pay HK
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fyh_transfer/Send/sendHomePage.dart';
import 'package:fyh_transfer/Order/orderHomePage.dart';
import 'package:fyh_transfer/Account/accountHomePage.dart';
class FYHTabbar extends StatefulWidget {
@override
FYHTabbarState createState() => FYHTabbarState();
}
class CustomerNotification extends Notification {
CustomerNotification(this.enable);
final bool enable;
}
class FYHTabbarState extends State<FYHTabbar>
{
List<Widget> pages = List<Widget>();
bool sendeEnable = false;
SendHomePage _sendHomePage = SendHomePage();
int _activeIndex = 1; //激活项
double _height = 48.0; //导航栏高度
double _floatRadius = 30; //悬浮图标半径
List _navs = [
Icons.search,
Icons.ondemand_video,
Icons.music_video,
]; //导航项
@override
void initState() {
super.initState();
pages..add(OrderHomePage())..add(_sendHomePage)..add(AccountHomePage());
}
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width - 40;
_floatRadius = _activeIndex == 1 ? 40 : 30;
return NotificationListener<CustomerNotification>(
onNotification: (notification) {
setState(() {
sendeEnable = notification.enable;
});
},
child: Container(
child: Stack(children: [
pages[_activeIndex],//tabbar要存放的页面
Positioned(//用Positioned绝对定位悬浮的TabBar
bottom: 15,
left: 20,
right: 20,
child: Container(
padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
width: width,
height: 58,
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
//所有图标
DecoratedBox(
decoration: BoxDecoration(
color: Color(0xFFf2f4f5), // 底色
shape: BoxShape.rectangle, // 默认值也是矩形
borderRadius:
new BorderRadius.circular(_height / 2), // 圆角度
boxShadow: [
BoxShadow(
color: Color(0xffc1c1c1),
offset: Offset(2.0, 2.0),
blurRadius: 50.0,
spreadRadius: 2.0)
],
),
child: SizedBox(
height: _height,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: _navs
.asMap()
.map((i, v) => MapEntry(
i,
GestureDetector(
child: Container(
color: Color(0xFFf2f4f5),
margin: EdgeInsets.all(0),
child: Icon(v,
color: _activeIndex == i
? Colors.pink
: Colors.grey),
width: width / 3 - 30,
height: _height - 10,
),
onTap: () {
_switchNav(i);
},
)))
.values
.toList(),
),
),
),
//浮动图标
Positioned(
bottom: 4,
left: (width) / 2 - _floatRadius,
child: DecoratedBox(
decoration:
ShapeDecoration(shape: CircleBorder(), shadows: [
BoxShadow(
blurRadius: 2,
offset: Offset(0, 2),
spreadRadius: 0,
color: _activeIndex == 1
? Colors.pink
: Colors.grey),
]),
child: GestureDetector(
child: CircleAvatar(
radius: _floatRadius, //浮动图标和圆弧之间设置8pixel间隙
backgroundColor: Color(0xfff2f4f5),
child: Icon(_navs[1],
color: sendeEnable && _activeIndex == 1
? Colors.pink
: Colors.black38)),
onTap: () {
_clickMiddleBtn();
},
),
),
),
],
),
),
)
]),
));
;
}
//中间按钮
_clickMiddleBtn() {
if (_activeIndex == 1) {
if (sendeEnable) {
print('send');
}
} else {
_switchNav(1);
}
}
//切换导航
_switchNav(int newIndex) {
print(newIndex);
double oldPosition = _activeIndex.toDouble();
double newPosition = newIndex.toDouble();
if (oldPosition != newPosition) {
setState(() {
_activeIndex = newIndex;
});
}
}
@override
void dispose() {
super.dispose();
}
}