起因
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來實現。 有其他騷操作的,請評論區告訴我,大家一起交流。