Flutter 解决系统BottomNavigationBar的水波纹问题

49 篇文章 0 订阅
47 篇文章 0 订阅

起因

Flutter 系统自带的BottomNavigationBar,在点击时item会有一个水波纹效果,产品并不想要这个(实际上这个水波纹有的时候还会卡住无法消失)。
网上暂时没有找到现成的,所以就自己撸一个。

PS:通过继承InteractiveInkFeature,也可以去除一些widget自带的水波纹(使用方法可以参考demo里的NoInkWellFactory类文件),不过bottom nav这里没法使用。

Step.1

首先整体结构,我们参照系统的,子Item的状态我们通过Provider进行管理,先创建一个BottomNavBarNoInk.

代码如下(说明我尽量写在注释里方便阅读):
class BottomNavBarNoInk extends StatefulWidget{

  IndexModel indexModel;

  final width;
  final height;
  List<BottomNavigationBarItem> items;

  int currentIndex;
  ValueChanged<int> onTap;

  BottomNavBarNoInk({@required this.width
    ,@required this.
    height,@required this.items,
    this.currentIndex,this.onTap}) : indexModel = IndexModel(currentIndex);


  @override
  State<StatefulWidget> createState() {

    return BottomNavBarNoInkState();
  }
}

class BottomNavBarNoInkState extends State<BottomNavBarNoInk> {

  List<Widget> 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进行封装.

Step.2

创建一个IndexModel对状态进行保存

代码如下

class IndexModel extends ChangeNotifier{
  int selectIndex;

  IndexModel(@required this.selectIndex);

  get index => selectIndex;

  setIndex(int index){
    selectIndex = index;
    notifyListeners();
  }

}

Step.3

在子Widget(BottomNoInkBarItem)中我们通过Consumer来获取到Provider管理的对象,并且根据这个对象的值来构造子widget,如果Provider的值变动,子widget也会同步刷新。

代码如下:

class BottomNoInkBarItem extends StatefulWidget{

  int index;
  BottomNavigationBarItem item;


  BottomNoInkBarItem({this.item,this.index});

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return BottomNoInkBarItemState();
  }

}

class BottomNoInkBarItemState extends State<BottomNoInkBarItem> {
  @override
  Widget build(BuildContext context) {

    return Consumer<IndexModel>(
      builder: (ctx,model,child){
        
        return Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              Stack(
                children: <Widget>[
                  //未激活状态
                  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地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值