Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2024
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 8.90 KB | None | 0 0
  1. class MyBottomNavBar extends StatefulWidget {
  2.   static const int _thresholdItemsNumber = 4;
  3.   static const Color clearColor = Colors.transparent;
  4.  
  5.   const MyBottomNavBar({
  6.     super.key,
  7.     required this.items,
  8.     required this.onTap, // required this.closeMenu,
  9.   });
  10.  
  11.   final List<MyNavBarItem> items;
  12.   final Function(int index) onTap;
  13.  
  14.   @override
  15.   State<MyBottomNavBar> createState() => _MyBottomNavBarState();
  16. }
  17.  
  18. class _MyBottomNavBarState extends State<MyBottomNavBar> {
  19.   PersistentBottomSheetController? _menuController;
  20.   late final bool showAdditionalMenu;
  21.  
  22.   @override
  23.   void initState() {
  24.     super.initState();
  25.     showAdditionalMenu = widget.items.length > 5;
  26.   }
  27.  
  28.   @override
  29.   Widget build(BuildContext context) {
  30.     return BlocProvider<NavBarBloc>(
  31.       create: (context) => NavBarBloc(),
  32.       child: Builder(builder: (context) {
  33.         return BlocBuilder<NavBarBloc, NavBarState>(
  34.           builder: (context, navBarState) {
  35.             return navBarState.map(
  36.               itemChanged: (value) {
  37.                 return SafeArea(
  38.                   bottom: true,
  39.                   child: SizedBox(
  40.                     height: 90,
  41.                     child: Container(
  42.                       color: _getBackgroundColor(context),
  43.                       padding: _edgeInsets4(),
  44.                       child: _getNavBar(
  45.                         context,
  46.                         value.index,
  47.                       ),
  48.                     ),
  49.                   ),
  50.                 );
  51.               },
  52.             );
  53.           },
  54.         );
  55.       }),
  56.     );
  57.   }
  58.  
  59.   Widget _getNavBar(BuildContext context, int selectedItemIndex) {
  60.     if (showAdditionalMenu) {
  61.       return _buildNavBarWithMenu(context, selectedItemIndex);
  62.     }
  63.     return _buildSimpleNavBar(context, selectedItemIndex);
  64.   }
  65.  
  66.   Widget _buildSimpleNavBar(BuildContext context, int selectedItemIndex) {
  67.     return Row(
  68.       crossAxisAlignment: CrossAxisAlignment.center,
  69.       mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  70.       children: widget.items.map(
  71.         (e) {
  72.           return _buildNavBarItem(
  73.             selectedItemIndex,
  74.             e,
  75.             context,
  76.             (int index) {
  77.               context.read<NavBarBloc>().add(NavBarEvent.indexChanged(widget.items.indexOf(e)));
  78.               widget.onTap(widget.items.indexOf(e));
  79.               _closeMenuIfOpened();
  80.             },
  81.           );
  82.         },
  83.       ).toList(),
  84.     );
  85.   }
  86.  
  87.   Expanded _buildNavBarItem(
  88.       int selectedItemIndex, MyNavBarItem e, BuildContext context, Function(int index) onTap) {
  89.     return Expanded(
  90.       flex: 2,
  91.       child: Container(
  92.         decoration: BoxDecoration(
  93.           borderRadius: BorderRadius.circular(4.0),
  94.           color: selectedItemIndex == widget.items.indexOf(e)
  95.               ? _getSelectedColor(context)
  96.               : MyBottomNavBar.clearColor,
  97.         ),
  98.         margin: const EdgeInsets.all(4.0),
  99.         child: InkWell(
  100.           enableFeedback: true,
  101.           onTap: () => onTap(widget.items.indexOf(e)),
  102.           child: e,
  103.         ),
  104.       ),
  105.     );
  106.   }
  107.  
  108.   Widget _buildNavBarWithMenu(BuildContext context, int index) {
  109.     return Row(
  110.       mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  111.       crossAxisAlignment: CrossAxisAlignment.center,
  112.       children: _buildElementsWithMenu(context, widget.items, index),
  113.     );
  114.   }
  115.  
  116.   EdgeInsets _edgeInsets4() => const EdgeInsets.all(4.0);
  117.  
  118.   Widget indexChanged(BuildContext context, int selectedIndex, bool showAdditionalMenu) {
  119.     return SizedBox(
  120.       width: MediaQuery.of(context).size.width,
  121.     );
  122.   }
  123.  
  124.   List<Widget> _buildElementsWithMenu(BuildContext context, List<MyNavBarItem> items, int selectedIndex) {
  125.     // const padding = EdgeInsets.all(8.0);
  126.     final bool showMoreIcon = items.length > MyBottomNavBar._thresholdItemsNumber;
  127.     final List<Widget> navBar = [];
  128.     for (var element in items) {
  129.       if (items.indexOf(element) < MyBottomNavBar._thresholdItemsNumber) {
  130.         navBar.add(
  131.           _buildNavBarItem(
  132.             selectedIndex,
  133.             element,
  134.             context,
  135.             (int index) {
  136.               context.read<NavBarBloc>().add(NavBarEvent.indexChanged(items.indexOf(element)));
  137.               widget.onTap(items.indexOf(element));
  138.               _closeMenuIfOpened();
  139.             },
  140.           ),
  141.         );
  142.       }
  143.     }
  144.     if (showMoreIcon) {
  145.       final bloc = context.read<NavBarBloc>();
  146.       navBar.add(
  147.         Expanded(
  148.           flex: 2,
  149.           child: Container(
  150.             padding: _edgeInsets4(),
  151.             decoration: BoxDecoration(
  152.               borderRadius: BorderRadius.circular(4.0),
  153.               color: selectedIndex >= MyBottomNavBar._thresholdItemsNumber
  154.                   ? _getSelectedColor(context)
  155.                   : MyBottomNavBar.clearColor,
  156.             ),
  157.             child: InkWell(
  158.               enableFeedback: true,
  159.               onTap: () {
  160.                 final menuList = items.sublist(4, items.length);
  161.                 _showBottomSheet(context, menuList, bloc);
  162.               },
  163.               child: const MyNavBarItem(
  164.                 iconData: MyIconData.more,
  165.                 label: 'More',
  166.               ),
  167.             ),
  168.           ),
  169.         ),
  170.       );
  171.     }
  172.     return navBar;
  173.   }
  174.  
  175.   void _closeMenuIfOpened() {
  176.     if (showAdditionalMenu && _menuController != null) {
  177.       _menuController?.close();
  178.     }
  179.   }
  180.  
  181.   void _showBottomSheet(context, menuList, bloc) {
  182.     _menuController = Scaffold.of(context).showBottomSheet<void>(
  183.       backgroundColor: Colors.white.withOpacity(0.2),
  184.       enableDrag: false,
  185.       shape: const RoundedRectangleBorder(
  186.         borderRadius: BorderRadius.only(topLeft: Radius.circular(0.0), topRight: Radius.circular(0.0)),
  187.       ),
  188.       (BuildContext context) {
  189.         return _buildMenu(menuList, context, bloc);
  190.       },
  191.       elevation: 5.0,
  192.     );
  193.   }
  194.  
  195.   Widget _buildMenu(menuList, BuildContext context, bloc) {
  196.     return InkWell(
  197.       enableFeedback: true,
  198.       splashColor: Colors.transparent,
  199.       focusColor: Colors.transparent,
  200.       highlightColor: Colors.transparent,
  201.       hoverColor: Colors.transparent,
  202.       overlayColor: MaterialStateProperty.all(Colors.transparent),
  203.       onTap: () {
  204.         _closeMenuIfOpened();
  205.       },
  206.       child: Container(
  207.         color: Colors.white.withOpacity(0.2),
  208.         child: Column(
  209.           mainAxisAlignment: MainAxisAlignment.end,
  210.           children: [
  211.             SizedBox(
  212.               // height: menuList.length * 65.0,
  213.               child: Container(
  214.                 decoration: BoxDecoration(
  215.                   color: _getBackgroundColor(context),
  216.                   borderRadius: const BorderRadius.only(
  217.                     topLeft: Radius.circular(20.0),
  218.                     topRight: Radius.circular(20.0),
  219.                   ),
  220.                 ),
  221.                 child: ListView.builder(
  222.                   itemCount: menuList.length,
  223.                   itemBuilder: (context, index) {
  224.                     return ListTile(
  225.                       leading: MyIcon(menuList[index].iconData),
  226.                       title: Text(menuList[index].label ?? ''),
  227.                       onTap: () {
  228.                         bloc.add(NavBarEvent.indexChanged(MyBottomNavBar._thresholdItemsNumber + index));
  229.                         widget.onTap(index + MyBottomNavBar._thresholdItemsNumber);
  230.                         _closeMenuIfOpened();
  231.                       },
  232.                     );
  233.                   },
  234.                 ),
  235.               ),
  236.             ),
  237.           ],
  238.         ),
  239.       ),
  240.     );
  241.   }
  242.  
  243.   Color _getBackgroundColor(BuildContext context) {
  244.     if (Theme.of(context).brightness == Brightness.dark) {
  245.       return Theme.of(context).primaryColor;
  246.     } else {
  247.       return Theme.of(context).scaffoldBackgroundColor;
  248.     }
  249.   }
  250.  
  251.   _getSelectedColor(BuildContext context) {
  252.     if (Theme.of(context).brightness != Brightness.dark) {
  253.       return Theme.of(context).primaryColor.withOpacity(0.2);
  254.     } else {
  255.       return Colors.white.withOpacity(0.2);
  256.     }
  257.   }
  258. }
  259.  
  260. class NavBarBloc extends Bloc<NavBarEvent, NavBarState> {
  261.   int _currentSelectedIndex = 0;
  262.  
  263.   int get currentIndex => _currentSelectedIndex;
  264.  
  265.   NavBarBloc()
  266.       : super(
  267.           _ItemChanged(0, DateTime.now()),
  268.         ) {
  269.     on<NavBarEvent>(
  270.       (event, emit) {
  271.         event.map(
  272.           indexChanged: (event) => _indexChanged(event, emit),
  273.         );
  274.       },
  275.     );
  276.   }
  277.  
  278.   void _indexChanged(_IndexChanged event, Emitter emit) {
  279.     if (_currentSelectedIndex != event.index) {
  280.       _currentSelectedIndex = event.index;
  281.       emit(
  282.         _ItemChanged(
  283.           _currentSelectedIndex,
  284.           DateTime.now(),
  285.         ),
  286.       );
  287.     }
  288.     _currentSelectedIndex = event.index;
  289.     emit(
  290.       _ItemChanged(
  291.         _currentSelectedIndex,
  292.         DateTime.now(),
  293.       ),
  294.     );
  295.   }
  296. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement