Flutter 解決系統BottomNavigationBar的水波紋問題

原由

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進行封裝.git

Step.2

建立一個IndexModel對狀態進行保存github

代碼以下bash

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也會同步刷新。ide

代碼以下:ui

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來實現。 有其餘騷操做的,請評論區告訴我,你們一塊兒交流。this

Demo地址spa

相關文章
相關標籤/搜索