美文网首页
Flutter仿Boss-5.Lottie实现的Tab切换

Flutter仿Boss-5.Lottie实现的Tab切换

作者: 一笑轮回吧 | 来源:发表于2024-04-04 21:28 被阅读0次

    效果

    Screen_Recording_20240405-210543.gif

    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

    相关文章

      网友评论

          本文标题:Flutter仿Boss-5.Lottie实现的Tab切换

          本文链接:https://www.haomeiwen.com/subject/diantjtx.html