今天在做一个需求,动态更新底部导航菜单BottomNavigationBar。本来很简单的一个需求却踩了一个坑,特此记录一下。
问题:
在更新菜单item数据后,通过setState((){})
刷新 BottomNavigationBar
_buildNavigationBar() {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
unselectedFontSize: 10,
selectedFontSize: 10,
backgroundColor: Colors.white,
items: barItemList,
currentIndex: _index,
onTap: (value) async {
},
);
}
这时候直接报错:
RangeError (index): Invalid value: Not in inclusive range 0..1: 2
字面意思是index越界了。
但通过打印确认了index的值并没有越界,那是哪里不对?
原因:
分析BottomNavigationBar源码后发现只有在它的initState()
才会去更新数据,
@override
void didUpdateWidget(BottomNavigationBar oldWidget) {
super.didUpdateWidget(oldWidget);
// No animated segue if the length of the items list changes.
if (widget.items.length != oldWidget.items.length) {
_resetState();
return;
}
……
但setState((){})并没有重新执行initState()
,只是重新build()
,所以BottomNavigationBar拿到的items长度还是旧的数据。
解决:
确定了原因解决方法就比较清晰了,就是需要让BottomNavigationBar重新创建,执行它的didUpdateWidget()
,方法是我们可以改变它的key来触发。
首先给它设置一个key:
var _navBarKey = UniqueKey();
_buildNavigationBar() {
return BottomNavigationBar(
key: _navBarKey,
type: BottomNavigationBarType.fixed,
unselectedFontSize: 10,
selectedFontSize: 10,
backgroundColor: Colors.white,
items: barItemList,
currentIndex: _index,
onTap: (value) async {
},
);
}
在更新完数据,只需要修改它的key就可以:
// 更新数据完成,刷新UI:
_navBarKey = UniqueKey();
以此类推,要让其他Widget重新创建也可以用同样的方法。
最后,补充说明一下UniqueKey()
:
UniqueKey是Flutter框架中的一个特殊类型,用于为Widget对象生成唯一的标识符。它是Key类的子类,用于标识Widget树中的一个节点,并确保它是唯一的。