效果
Lottie引入
根据自己项目适配的Flutter版本引入对应的Lottie版本。
lottie: ^3.1.0
实现
- lottie 文件,直接下载Boss APK,解压出来就可以拿到。
- 代码:
LottieBottomBarItem
import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:lottie/lottie.dart'; /// Lottie BottomBarItem class LottieBottomBarItem extends StatefulWidget { // Tab 名字 final String tabName; // Tab 图标 final String tabIcon; // 默认颜色 final Color tabTextColor; // 选中颜色 final Color tabTextSelectedColor; // Tab对应索引 final int tabIndex; // 点击回调 final Function(int) onTap; // 是否选中 final bool isChecked; // 角标 final int badger; const LottieBottomBarItem({ Key? key, required this.tabName, required this.tabIcon, required this.onTap, required this.tabIndex, this.tabTextColor = Colors.grey, this.tabTextSelectedColor = Colors.black, this.isChecked = false, this.badger = 0, }) : super(key: key); @override State<LottieBottomBarItem> createState() => _BottomBarItemState(); } class _BottomBarItemState extends State<LottieBottomBarItem> with TickerProviderStateMixin { AnimationController? _animationController; @override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 500)); if (widget.isChecked) { _animationController?.forward(); } } @override void didUpdateWidget(covariant LottieBottomBarItem oldWidget) { super.didUpdateWidget(oldWidget); if (!widget.isChecked && oldWidget != widget) { _animationController?.reset(); } } @override void dispose() { _animationController?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return InkWell( child: Stack( alignment: Alignment.bottomCenter, children: [ Positioned( child: Column( children: [ Lottie.asset( widget.tabIcon, repeat: false, controller: _animationController, width: 35.w, height: 30.w, ), Text( widget.tabName, style: TextStyle( color: widget.isChecked ? widget.tabTextSelectedColor : widget.tabTextColor, fontSize: 12.sp, ), ) ], ), ), Visibility( visible: widget.badger > 0, child: Positioned( right: 30.w, top: 10.w, child: ClipOval( child: Container( alignment: Alignment.center, color: Colors.red, width: 8, height: 8, ), ), ), ) ], ), onTap: () { widget.onTap(widget.tabIndex); _animationController?.forward(); }, ); } }
HomePage
class HomePage extends StatefulWidget with RouteQueryMixin { HomePage({Key? key}) : super(key: key); @override State<StatefulWidget> createState() { return HomeState(); } } class HomeState extends PageState<HomePage> with AutomaticKeepAliveClientMixin { final logic = Get.put(HomeLogic()); @override void initState() { super.initState(); logic.handleCurrentIndex(params: widget.routeParams); } @override Widget build(BuildContext context) { return Scaffold( body: _homeBodyWidget(context), ); } Widget _homeBodyWidget(BuildContext context) { return Scaffold( body: Stack( alignment: Alignment.bottomCenter, children: <Widget>[ // 子布局 PageView( controller: logic.pageController, physics: const NeverScrollableScrollPhysics(), children: _bodyContentWidget(), onPageChanged: (index) { logic.state.currentIndex.value = index; }, ), ], ), // 底部栏 bottomNavigationBar: Obx( () => BottomAppBar( elevation: 5.0, height: 65, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.center, children: List.generate( logic.state.homeBottomBar.length, (index) => Expanded( child: LottieBottomBarItem( tabName: logic.state.homeBottomBar[index].tabName, tabIcon: logic.state.homeBottomBar[index].tabIcon, tabIndex: index, onTap: (index) { logic.state.currentIndex.value = index; logic.pageController.jumpToPage(index); }, isChecked: logic.state.currentIndex.value == index, ), ), )), ), ), ); } @override bool get wantKeepAlive => true; /// 子布局集合 List<Widget> _bodyContentWidget() { return logic.state.homeBottomBar.map((item) => item.child).toList(); } }
HomeState
class HomeTab { HomeTab({ required this.tabName, required this.tabIcon, required this.child, this.badger = 0, }); String tabName; String tabIcon; Widget child; int badger; } class HomeState { ///当前索引 RxInt currentIndex = 0.obs; ///底部按钮 final List<HomeTab> homeBottomBar = [ HomeTab( tabName: '职位', tabIcon: 'assets/lottie/tab/zhiwei.json', child: const WorkPage()), HomeTab( tabName: '有了', tabIcon: 'assets/lottie/tab/youle.json', child: const YoulePage()), HomeTab( tabName: '消息', tabIcon: 'assets/lottie/tab/xiaoxi-c.json', child: const MessagePage()), HomeTab( tabName: '我的', tabIcon: 'assets/lottie/tab/wode-c.json', child: const MinePage()), ]; }
HomeLogic
class HomeLogic extends GetxController with HttpApi { final HomeState state = HomeState(); late PageController pageController; /// 处理tab默认显示索引 void handleCurrentIndex({required Map<String, dynamic> params}) { int size = state.homeBottomBar.length; if (params != null) { int tabIndex = params["tabIndex"] ?? 0; // 默认加载页面 if (tabIndex >= size) { state.currentIndex.value = size - 1; } else { state.currentIndex.value = tabIndex; } } // 初始化tab控制器 pageController = PageController(initialPage: state.currentIndex.value, keepPage: true); } }
详情:github.com/yixiaolunhui/flutter_project