Flutter development practice-implementing custom bottomNavigationBar style awesome_bottom_bar
During the development process, you need to customize the bottomNavigationBar style. You can customize the implementation. The awesome_bottom_bar library is used here.
一、awesome_bottom_bar
Introduce awesome_bottom_bar in pubspec.yaml
awesome_bottom_bar: ^1.2.2
2. Implement custom bottomNavigationBar
Switch interface using PageView.builder
PageView is a very important component. For example, most apps include Tab page changing effects, picture rotation, and Douyin up and down page switching video functions, etc., which can all be implemented using PageView.
PageView({
Key? key,
this.scrollDirection = Axis.horizontal, // 滑动方向
this.reverse = false,
PageController? controller,
this.physics,
List<Widget> children = const <Widget>[],
this.onPageChanged,
//每次滑动是否强制切换整个页面,如果为false,则会根据实际的滑动距离显示页面
this.pageSnapping = true,
//主要是配合辅助功能用的,后面解释
this.allowImplicitScrolling = false,
//后面解释
this.padEnds = true,
})
Use PageView.builder to switch interfaces. When clicking different tabs, you can use PageController to switch.
PageView.builder(
itemBuilder: (BuildContext context, int index) {
return KeepAliveWrapper(
child: subMainPages[index], keepAlive: true);
},
itemCount: subMainPages.length,
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
onPageChanged: (index) {
_selectedIndex = index;
_animationControllerList[_selectedIndex!].forward();
_animationControllerList[_lastSelectedIndex!].reverse();
},
),
),
bottomNavigationBar using default effect
bottomNavigationBar: BottomBarDefault(
items: buildTabItems(context),
backgroundColor: Colors.white,
color: Colors.black87,
colorSelected: Colors.amber,
indexSelected: _selectedIndex,
duration: Duration(milliseconds: 200),
onTap: (int index) => setState(() {
_lastSelectedIndex = _selectedIndex;
_pageController.jumpToPage(index);
}),
),
When a special style of bottomNavigationBar is needed, such as the following triangle style that will highlight after clicking
bottomNavigationBar: BottomBarInspiredInside(
items: [
TabItem(
icon: Icons.home_outlined,
title: S.of(context).home,
),
TabItem(
icon: Icons.qr_code_scanner_outlined,
title: S.of(context).qrScan,
),
TabItem(
icon: Icons.nature_outlined,
title: S.of(context).mine,
count: Container(
padding: EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
width: 1.0,
style: BorderStyle.solid,
),
color: Colors.red,
borderRadius: BorderRadius.all(
Radius.circular(20.0),
),
// gradient: LinearGradient(
// begin: Alignment.topLeft,
// end: Alignment.bottomRight,
// colors: [
// Colors.red.withOpacity(0.5),
// Colors.red.withOpacity(0.3),
// Colors.red.withOpacity(1.0),
// ],
// ),
),
child: Text(
"99",
style: TextStyle(
fontSize: 10,
color: Colors.white,
fontWeight: FontWeight.w500),
),
),
)
],
backgroundColor: Colors.lightBlue,
color: Colors.white,
colorSelected: Colors.white,
indexSelected: _selectedIndex,
duration: Duration(milliseconds: 200),
onTap: (int index) => setState(() {
_pageController.jumpToPage(index);
}),
itemStyle: ItemStyle.hexagon,
chipStyle:
const ChipStyle(isHexagon: true, background: Colors.blueAccent),
),
The complete example code is as follows
class MainTabNavigator extends StatefulWidget {
const MainTabNavigator({
Key? key}) : super(key: key);
State<MainTabNavigator> createState() => _MainTabNavigatorState();
}
class _MainTabNavigatorState extends State<MainTabNavigator>
with TickerProviderStateMixin {
PageController _pageController = PageController();
int _selectedIndex = 0;
late DateTime _lastPressed;
List<Widget> subMainPages = [];
late List<AnimationController> _animationControllerList;
late List<Animation<double>> _animationList;
int? _lastSelectedIndex = 0;
void initState() {
// 设置默认的
subMainPages = mainPages;
super.initState();
_animationControllerList = List<AnimationController>.empty(growable: true);
_animationList = List<Animation<double>>.empty(growable: true);
for (int i = 0; i < subMainPages.length; ++i) {
_animationControllerList.add(AnimationController(
duration: Duration(milliseconds: 200), vsync: this));
_animationList.add(Tween(begin: 0.0, end: 5.0)
.chain(CurveTween(curve: Curves.ease))
.animate(_animationControllerList[i]));
}
WidgetsBinding.instance.addPostFrameCallback((_) {
_animationControllerList[_selectedIndex!].forward();
});
}
void animationDispose() {
for (int i = 0; i < subMainPages.length; ++i) {
_animationControllerList[i].dispose();
}
}
void dispose() {
// TODO: implement dispose
animationDispose();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: WillPopScope(
onWillPop: () async {
if (_lastPressed == null ||
DateTime.now().difference(_lastPressed) > Duration(seconds: 1)) {
//两次点击间隔超过1秒则重新计时
_lastPressed = DateTime.now();
return false;
}
return true;
},
child: PageView.builder(
itemBuilder: (BuildContext context, int index) {
return KeepAliveWrapper(
child: subMainPages[index], keepAlive: true);
},
itemCount: subMainPages.length,
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
onPageChanged: (index) {
_selectedIndex = index;
_animationControllerList[_selectedIndex!].forward();
_animationControllerList[_lastSelectedIndex!].reverse();
},
),
),
// bottomNavigationBar: BottomBarDefault(
// items: buildTabItems(context),
// backgroundColor: Colors.white,
// color: Colors.black87,
// colorSelected: Colors.amber,
// indexSelected: _selectedIndex,
// duration: Duration(milliseconds: 200),
// onTap: (int index) => setState(() {
// _lastSelectedIndex = _selectedIndex;
// _pageController.jumpToPage(index);
// }),
// ),
bottomNavigationBar: BottomBarInspiredInside(
items: [
TabItem(
icon: Icons.home_outlined,
title: S.of(context).home,
),
TabItem(
icon: Icons.qr_code_scanner_outlined,
title: S.of(context).qrScan,
),
TabItem(
icon: Icons.nature_outlined,
title: S.of(context).mine,
count: Container(
padding: EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
width: 1.0,
style: BorderStyle.solid,
),
color: Colors.red,
borderRadius: BorderRadius.all(
Radius.circular(20.0),
),
// gradient: LinearGradient(
// begin: Alignment.topLeft,
// end: Alignment.bottomRight,
// colors: [
// Colors.red.withOpacity(0.5),
// Colors.red.withOpacity(0.3),
// Colors.red.withOpacity(1.0),
// ],
// ),
),
child: Text(
"99",
style: TextStyle(
fontSize: 10,
color: Colors.white,
fontWeight: FontWeight.w500),
),
),
)
],
backgroundColor: Colors.lightBlue,
color: Colors.white,
colorSelected: Colors.white,
indexSelected: _selectedIndex,
duration: Duration(milliseconds: 200),
onTap: (int index) => setState(() {
_pageController.jumpToPage(index);
}),
itemStyle: ItemStyle.hexagon,
chipStyle:
const ChipStyle(isHexagon: true, background: Colors.blueAccent),
),
// bottomNavigationBar: FlashyTabBar(
// selectedIndex: _selectedIndex,
// showElevation: true,
// onItemSelected: (index) => setState(() {
// _pageController.jumpToPage(index);
// }),
// items: [
// FlashyTabBarItem(
// icon: Icon(Icons.home_outlined),
// title: Text(S.of(context).home),
// ),
// FlashyTabBarItem(
// icon: Icon(Icons.qr_code_scanner_outlined),
// title: Text(S.of(context).qrScan),
// ),
// FlashyTabBarItem(
// icon: Icon(Icons.nature_outlined),
// title: Text(S.of(context).mine),
// ),
// ],
// ), // bottomNavigationBar: BottomNavigationBar(
);
}
List<TabItem> buildTabItems(BuildContext context) {
TabItem homeItem = TabItem(
icon: Icons.home_outlined,
title: S.of(context).home,
count: buildTabItem(context, 0),
);
TabItem qsItem = TabItem(
icon: Icons.qr_code_scanner_outlined,
title: S.of(context).qrScan,
count: buildTabItem(context, 1),
);
TabItem discoveryItem = TabItem(
icon: Icons.location_searching_outlined,
title: S.of(context).discovery,
count: buildTabItem(context, 2),
);
TabItem mineItem = TabItem(
icon: Icons.nature_outlined,
title: S.of(context).mine,
count: buildTabItem(context, 3),
);
return [homeItem, qsItem, discoveryItem, mineItem];
}
Widget buildTabItem(BuildContext context, int index) {
return AnimatedBuilder(
animation: _animationList[index],
builder: (BuildContext context, Widget? child) {
return Container(
margin: EdgeInsets.only(
top: _animationList[index].value,
),
child: child,
);
},
child: buildTabItemCount(context),
);
}
Widget buildTabItemCount(BuildContext context) {
return Container(
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
width: 1.0,
style: BorderStyle.solid,
),
color: Colors.red,
borderRadius: const BorderRadius.all(
Radius.circular(30.0),
),
// gradient: LinearGradient(
// begin: Alignment.topLeft,
// end: Alignment.bottomRight,
// colors: [
// Colors.red.withOpacity(0.5),
// Colors.red.withOpacity(0.3),
// Colors.red.withOpacity(1.0),
// ],
// ),
),
child: const Text(
"99",
style: TextStyle(
fontSize: 10, color: Colors.white, fontWeight: FontWeight.w500),
),
);
}
}
3. Summary
Flutter development practice-customize bottomNavigationBar style.
https://blog.csdn.net/gloryFlow/article/details/132761946
Study and record, keep improving every day.