一般来说,写 BottomNavigationBar 会使用这个方法,官方文件,这个是官方的范例。
今天我想要介绍,如何从简单的变成有动画的感觉。
今日的程序码 => GITHUB
制作一个 Widget
,然後里面放一个 Row
,Row
里面放一个可以点击的 AnimatedContainer
,然後设定 icon 的图示和动画。这个 Widget
会有一个初始的 pageIndex
,BottomNavigator
也会有一个 pageIndex
,这两个的 index
要设为一样。在这个自定义的 Widget
里面,会有一个 callBack
可以让 BottomNavigator
拿到这个自定义 Widget
里面被点击的 index
。
这边我是把它建立成 2 个物件,有兴趣的话(可以自行尝试变成一个物件)
class BarStyle {
final double fontSize, iconSize;
final FontWeight fontWeight;
BarStyle(
{this.fontSize = 18.0,
this.iconSize = 32.0,
this.fontWeight = FontWeight.w600});
}
class BarItemData {
final String text;
final IconData iconData;
final Color color;
BarItemData(this.text, this.iconData, this.color);
}
控制 bottomNavigationBar
的页面
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
/// the index of pageItem
/// 画面的 index
int pageIndex = 0;
/// 宣告一个 List,等等要放对应的 Page 进去
List<Widget> pageItem = [];
@override
void initState() {
super.initState();
/// 每一页对应的 Page 是什麽
pageItem = [HomePage(), NotifyScreen(), UserProfile(), SettingApp()];
}
/// Object<BarItem> of List
/// List 里面包一个 自定义的物件 BarItem
final List<BarItemData> barItems = [
BarItemData("Home", Icons.home, Color(0xFF498AEF)),
BarItemData("Notify", Icons.notifications_active, Colors.red),
BarItemData("Profile", Icons.person_outline, Colors.teal),
BarItemData("Setting", Icons.menu, Colors.purple)
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: IndexedStack(
index: pageIndex,
children: pageItem,
),
bottomNavigationBar: AnimationBottomBar(
barItemsData: barItems,
// animationDuration: const Duration(milliseconds: 500), 非必填
// curves: Curves.easeInOut, 非必填
barStyle: BarStyle(
fointSize: 20.0, fontWeight: FontWeight.w400, iconSize: 30.0),
changePageIndex: (int index) {
/// when bottomBar on Tap will return the bottomBar index
/// 会回传被点击到的 bottomBar index
setState(() {
pageIndex = index;
});
},
),
);
}
}
自定义的客制化 BottomBar 的 Item
class AnimationBottomBar extends StatefulWidget {
/// get data of List<BarItem>
/// 取得 BarItem 的资料
final List<BarItemData> _barItemsData;
/// get animation duration time
/// 取得 animation 的延迟时间
final Duration _animationDuration;
/// get data of List<BarItem>
/// 取得 BarItem 的资料
final BarStyle _barStyle;
/// callBack will return the index of the bottombar that was clicked
/// callBack 回传被点击到的 index
final void Function(int index) _changePageIndex;
/// animation
/// 动画的效果
final Curve _curves;
const AnimationBottomBar(
{Key? key,
required List<BarItemData> barItemsData,
Duration animationDuration = const Duration(milliseconds: 500),
Curve curves = Curves.easeInOut,
required BarStyle barStyle,
required Function(int index) changePageIndex})
: _barItemsData = barItemsData,
_animationDuration = animationDuration,
_barStyle = barStyle,
_curves = curves,
_changePageIndex = changePageIndex,
super(key: key);
@override
_AnimationBottomBarState createState() => _AnimationBottomBarState();
}
class _AnimationBottomBarState extends State<AnimationBottomBar>
with TickerProviderStateMixin {
/// init selectedBarIndex = 0;
/// 初始化 selectedBarIndex = 0;
int selectedBarIndex = 0;
@override
Widget build(BuildContext context) {
return Material(
elevation: 10.0,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _buildBarItems()),
),
);
}
/// save the single data of barItemsData into the List
/// 将 barItemsData 的单笔资料存入 List 里面
List<Widget> _buildBarItems() {
/// init _barItem List
List<Widget> _barItems = [];
for (int i = 0; i < widget._barItemsData.length; i++) {
BarItemData item = widget._barItemsData[i];
bool isSelected = selectedBarIndex == i;
_barItems.add(_customBarItem(i, isSelected, item));
}
return _barItems;
}
/// build CustomBarItem in BottomNavigatorBar
/// 建立客制化的 BarItem 样式
InkWell _customBarItem(int i, bool isSelected, BarItemData item) {
return InkWell(
splashColor: Colors.transparent,
onTap: () {
setState(() {
selectedBarIndex = i;
widget._changePageIndex(selectedBarIndex);
});
},
child: AnimatedContainer(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
duration: widget._animationDuration,
decoration: BoxDecoration(
color:
isSelected ? item.color.withOpacity(0.15) : Colors.transparent,
borderRadius: BorderRadius.all(Radius.circular(30.0))),
child: Row(
children: <Widget>[
Icon(
item.iconData,
color: isSelected ? item.color : Colors.black,
size: widget._barStyle.iconSize,
),
SizedBox(width: 10.0),
AnimatedSize(
duration: widget._animationDuration,
curve: widget._curves,
vsync: this,
child: Text(
isSelected ? item.text : "",
style: TextStyle(
color: item.color,
fontWeight: widget._barStyle.fontWeight,
fontSize: widget._barStyle.fontSize),
),
),
],
),
),
);
}
}
>>: Day4-React Hook 篇-认识 useRef & useImperativeHandle
晚上在看线图的时候,发现铼德2349有几个观点可以提出来跟大家分享。 在今年1月初时,跌破季线,这时...
ARM 与 x86 谁更对你胃口呢? 我们在之前的文章内讨论了很多 ARM 与 x86 的差异,互相...
#photos{position:absolute;width:calc(600px*6);z-i...
天亮了 昨晚是平安夜 关於迷雾森林故事 旋木 随着蓝调漫节奏 大家跟着音浪一起流动 阿虎也拿着麦克风...
後端工程师最必须要会的其中一个技能,就是对资料库的操作,我相信很少有後端工程师可以完全不用学到对资料...