Flutter 系统自带的BottomNavigationBar,在点击时item会有一个水波纹效果,产品并不想要这个(实际上这个水波纹有的时候还会卡住无法消失)。
网上暂时没有找到现成的,所以就自己撸一个。
PS:通过继承InteractiveInkFeature,也可以去除一些widget自带的水波纹(使用方法可以参考demo里的NoInkWellFactory类文件),不过bottom nav这里没法使用。
首先整体结构,我们参照系统的,子Item的状态我们通过Provider进行管理,先创建一个BottomNavBarNoInk.
代码如下(说明我尽量写在注释里方便阅读):
class BottomNavBarNoInk extends StatefulWidget{
IndexModel indexModel;
final width;
final height;
List items;
int currentIndex;
ValueChanged onTap;
BottomNavBarNoInk({@required this.width
,@required this.
height,@required this.items,
this.currentIndex,this.onTap}) : indexModel = IndexModel(currentIndex);
@override
State createState() {
return BottomNavBarNoInkState();
}
}
class BottomNavBarNoInkState extends State {
List barItems = [];
@override
void initState() {
// TODO: implement initState
super.initState();
transfer2Widget();
}
//根据items创建对应的widget
transfer2Widget(){
for(int i=0; i< widget.items.length;i++){
barItems.add(GestureDetector(
onTap: (){
widget.onTap(i);
//更新model的值
model?.setIndex(i);
},
child: BottomNoInkBarItem(item: widget.items[i],index: i,),
));
}
}
//用于保存当前第几个item被点击
IndexModel model ;
@override
Widget build(BuildContext context) {
//通过provider 保存IndexModel,
//子widget可以共享这个model并根据内部数据的变更自动刷新
return ChangeNotifierProvider(
create: (ctx){
model = IndexModel(widget.currentIndex);
return model;
},
child:Container(
width: widget.width,
height: widget.height,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: barItems,
),
) ,
) ;
}
这里我们依然使用系统的BottomNavigationBarItem对item进行封装.
创建一个IndexModel对状态进行保存
代码如下
class IndexModel extends ChangeNotifier{
int selectIndex;
IndexModel(@required this.selectIndex);
get index => selectIndex;
setIndex(int index){
selectIndex = index;
notifyListeners();
}
}
在子Widget(BottomNoInkBarItem)中我们通过Consumer来获取到Provider管理的对象,并且根据这个对象的值来构造子widget,如果Provider的值变动,子widget也会同步刷新。
代码如下:
class BottomNoInkBarItem extends StatefulWidget{
int index;
BottomNavigationBarItem item;
BottomNoInkBarItem({this.item,this.index});
@override
State createState() {
// TODO: implement createState
return BottomNoInkBarItemState();
}
}
class BottomNoInkBarItemState extends State {
@override
Widget build(BuildContext context) {
return Consumer(
builder: (ctx,model,child){
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Stack(
children: [
//未激活状态
Offstage(
offstage: model.index == widget.index,
child: widget.item.icon,
),
Offstage(
offstage: model.index != widget.index,
child: widget.item.activeIcon,
),
],
),
///title
widget.item.title
],
),
);
},
);
}
}
至此功能就完成了,因为我的项目用到了Provider,所以这里便直接使用了。如果不想用Provider,也可以使用stream来实现。
有其他骚操作的,请评论区告诉我,大家一起交流。
Demo地址