LCOV - code coverage report
Current view: top level - navigation - custom_bottom_navbar.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 51 51 100.0 %
Date: 2024-11-26 10:38:40 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/material.dart';
       2             : 
       3             : /// Represents an individual navigation item within the [CustomBottomNavBar].
       4             : ///
       5             : /// The [NavigationItem] class encapsulates the information required for each
       6             : /// item in the bottom navigation bar, including the target page, icon, and label.
       7             : class NavigationItem {
       8             :   /// The page to navigate to when this item is selected.
       9             :   ///
      10             :   /// This should be a widget that represents the content associated with the navigation item.
      11             :   final Widget page;
      12             : 
      13             :   /// The icon to display for this navigation item.
      14             :   ///
      15             :   /// Typically, this is an [Icon] widget that visually represents the item's purpose.
      16             :   final Icon icon;
      17             : 
      18             :   /// The label text for this navigation item.
      19             :   ///
      20             :   /// This text appears below the icon and provides a descriptive name for the item.
      21             :   final String label;
      22             : 
      23             :   /// Creates a [NavigationItem] with the specified [page], [icon], and [label].
      24             :   ///
      25             :   /// All parameters are required and must not be null.
      26           1 :   const NavigationItem({
      27             :     required this.page,
      28             :     required this.icon,
      29             :     required this.label,
      30             :   });
      31             : }
      32             : 
      33             : /// A customizable bottom navigation bar that manages navigation between different pages.
      34             : ///
      35             : /// The [CustomBottomNavBar] widget provides a styled bottom navigation bar that allows
      36             : /// users to switch between various pages in the app. It integrates seamlessly with a
      37             : /// [PageView] to handle page transitions and maintains the selected index state.
      38             : ///
      39             : /// **Example usage:**
      40             : /// ```dart
      41             : /// List<NavigationItem> navItems = [
      42             : ///   NavigationItem(
      43             : ///     page: HomePage(),
      44             : ///     icon: Icon(Icons.home),
      45             : ///     label: 'Home',
      46             : ///   ),
      47             : ///   NavigationItem(
      48             : ///     page: SearchPage(),
      49             : ///     icon: Icon(Icons.search),
      50             : ///     label: 'Search',
      51             : ///   ),
      52             : ///   NavigationItem(
      53             : ///     page: ProfilePage(),
      54             : ///     icon: Icon(Icons.person),
      55             : ///     label: 'Profile',
      56             : ///   ),
      57             : /// ];
      58             : ///
      59             : /// CustomBottomNavBar(
      60             : ///   items: navItems,
      61             : ///   backgroundColor: Colors.white,
      62             : ///   selectedItemColor: Colors.blue,
      63             : ///   unselectedItemColor: Colors.grey,
      64             : ///   elevation: 10.0,
      65             : ///   type: BottomNavigationBarType.fixed,
      66             : /// );
      67             : /// ```
      68             : class CustomBottomNavBar extends StatefulWidget {
      69             :   /// A list of [NavigationItem]s to display in the bottom navigation bar.
      70             :   ///
      71             :   /// Each [NavigationItem] defines a page, icon, and label for a navigation tab.
      72             :   final List<NavigationItem> items;
      73             : 
      74             :   /// The background color of the bottom navigation bar.
      75             :   ///
      76             :   /// If not specified, it defaults to the theme's `colorScheme.surface`.
      77             :   final Color? backgroundColor;
      78             : 
      79             :   /// The color of the selected navigation item.
      80             :   ///
      81             :   /// If not specified, it defaults to the theme's `colorScheme.primary`.
      82             :   final Color? selectedItemColor;
      83             : 
      84             :   /// The color of the unselected navigation items.
      85             :   ///
      86             :   /// If not specified, it defaults to the theme's `unselectedWidgetColor`.
      87             :   final Color? unselectedItemColor;
      88             : 
      89             :   /// The elevation (shadow depth) of the bottom navigation bar.
      90             :   ///
      91             :   /// If not specified, it defaults to the theme's `bottomNavigationBarTheme.elevation`
      92             :   /// or `8.0` if the theme does not provide one.
      93             :   final double? elevation;
      94             : 
      95             :   /// The type of the bottom navigation bar.
      96             :   ///
      97             :   /// Determines the layout behavior of the items. If not specified, it defaults
      98             :   /// to the theme's `bottomNavigationBarTheme.type` or `BottomNavigationBarType.shifting`.
      99             :   final BottomNavigationBarType? type;
     100             : 
     101             :   /// The font size of the selected item's label.
     102             :   ///
     103             :   /// If not specified, it defaults to the theme's `bottomNavigationBarTheme.selectedLabelStyle.fontSize`
     104             :   /// or `14.0`.
     105             :   final double? selectedFontSize;
     106             : 
     107             :   /// The font size of the unselected items' labels.
     108             :   ///
     109             :   /// If not specified, it defaults to the theme's `bottomNavigationBarTheme.unselectedLabelStyle.fontSize`
     110             :   /// or `12.0`.
     111             :   final double? unselectedFontSize;
     112             : 
     113             :   /// Whether to show labels for the selected items.
     114             :   ///
     115             :   /// If not specified, it defaults to the theme's `bottomNavigationBarTheme.showSelectedLabels`
     116             :   /// or `true`.
     117             :   final bool? showSelectedLabels;
     118             : 
     119             :   /// Whether to show labels for the unselected items.
     120             :   ///
     121             :   /// If not specified, it defaults to the theme's `bottomNavigationBarTheme.showUnselectedLabels`
     122             :   /// or `true`.
     123             :   final bool? showUnselectedLabels;
     124             : 
     125             :   /// The icon theme for the selected navigation item.
     126             :   ///
     127             :   /// If not specified, it defaults to the theme's `bottomNavigationBarTheme.selectedIconTheme`
     128             :   /// or an [IconThemeData] with size `24.0`.
     129             :   final IconThemeData? selectedIconTheme;
     130             : 
     131             :   /// The icon theme for the unselected navigation items.
     132             :   ///
     133             :   /// If not specified, it defaults to the theme's `bottomNavigationBarTheme.unselectedIconTheme`
     134             :   /// or an [IconThemeData] with size `20.0`.
     135             :   final IconThemeData? unselectedIconTheme;
     136             : 
     137             :   /// The padding to apply around each navigation item's icon.
     138             :   ///
     139             :   /// If not specified, it defaults to `EdgeInsets.zero`.
     140             :   final EdgeInsetsGeometry? itemPadding;
     141             : 
     142             :   /// The external margin around the bottom navigation bar.
     143             :   ///
     144             :   /// If not specified, it defaults to `EdgeInsets.all(0)`.
     145             :   final EdgeInsetsGeometry? margin;
     146             : 
     147             :   /// Creates a [CustomBottomNavBar] with the specified properties.
     148             :   ///
     149             :   /// The [items] parameter is required and must contain at least two [NavigationItem]s.
     150           1 :   const CustomBottomNavBar({
     151             :     super.key,
     152             :     required this.items,
     153             :     this.backgroundColor,
     154             :     this.selectedItemColor,
     155             :     this.unselectedItemColor,
     156             :     this.elevation,
     157             :     this.type,
     158             :     this.selectedFontSize,
     159             :     this.unselectedFontSize,
     160             :     this.showSelectedLabels,
     161             :     this.showUnselectedLabels,
     162             :     this.selectedIconTheme,
     163             :     this.unselectedIconTheme,
     164             :     this.itemPadding,
     165             :     this.margin,
     166             :   });
     167             : 
     168           1 :   @override
     169           1 :   State<CustomBottomNavBar> createState() => _CustomBottomNavBarState();
     170             : }
     171             : 
     172             : class _CustomBottomNavBarState extends State<CustomBottomNavBar> {
     173             :   /// The index of the currently selected navigation item.
     174             :   ///
     175             :   /// Initialized to `0`, representing the first item in the [widget.items] list.
     176             :   int _selectedIndex = 0;
     177             : 
     178             :   /// Controller for managing page transitions in the [PageView].
     179             :   ///
     180             :   /// Prevents users from swiping between pages manually by setting
     181             :   /// [physics] to [NeverScrollableScrollPhysics].
     182             :   PageController pageController = PageController();
     183             : 
     184             :   /// Handles taps on navigation items.
     185             :   ///
     186             :   /// Animates the [PageView] to the selected page and updates the [_selectedIndex].
     187           1 :   void _onItemTapped(int index) {
     188           2 :     pageController.animateToPage(
     189             :       index,
     190             :       duration: const Duration(milliseconds: 500),
     191             :       curve: Curves.ease,
     192             :     );
     193           2 :     setState(() {
     194           1 :       _selectedIndex = index;
     195             :     });
     196             :   }
     197             : 
     198           1 :   @override
     199             :   Widget build(BuildContext context) {
     200             :     // Retrieve the current theme's BottomNavigationBarThemeData.
     201           2 :     final bottomNavBarTheme = Theme.of(context).bottomNavigationBarTheme;
     202             : 
     203           1 :     return Scaffold(
     204             :       // The main content area that displays the selected page.
     205           1 :       body: PageView(
     206           1 :         controller: pageController,
     207             :         physics: const NeverScrollableScrollPhysics(),
     208             :         // Disables swipe navigation.
     209           6 :         children: widget.items.map((e) => e.page).toList(),
     210             :       ),
     211             :       // The bottom navigation bar wrapped in a styled Card.
     212           1 :       bottomNavigationBar: Card(
     213           2 :         margin: widget.margin ?? const EdgeInsets.all(0),
     214           3 :         elevation: widget.elevation ?? bottomNavBarTheme.elevation ?? 8.0,
     215           2 :         color: widget.backgroundColor ??
     216           1 :             bottomNavBarTheme.backgroundColor ??
     217           3 :             Theme.of(context).colorScheme.surface,
     218             :         shape: const RoundedRectangleBorder(
     219             :           borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
     220             :         ),
     221           1 :         child: ClipRRect(
     222             :           borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
     223             :           clipBehavior: Clip.hardEdge,
     224           1 :           child: BottomNavigationBar(
     225             :             elevation: 0,
     226             :             backgroundColor: Colors.transparent,
     227             :             // Allows Card's color to show.
     228           2 :             type: widget.type ??
     229           1 :                 bottomNavBarTheme.type ??
     230             :                 BottomNavigationBarType.shifting,
     231           2 :             selectedItemColor: widget.selectedItemColor ??
     232           1 :                 bottomNavBarTheme.selectedItemColor ??
     233           3 :                 Theme.of(context).colorScheme.primary,
     234           2 :             unselectedItemColor: widget.unselectedItemColor ??
     235           1 :                 bottomNavBarTheme.unselectedItemColor ??
     236           2 :                 Theme.of(context).unselectedWidgetColor,
     237           2 :             selectedFontSize: widget.selectedFontSize ??
     238           1 :                 bottomNavBarTheme.selectedLabelStyle?.fontSize ??
     239             :                 14.0,
     240           2 :             unselectedFontSize: widget.unselectedFontSize ??
     241           1 :                 bottomNavBarTheme.unselectedLabelStyle?.fontSize ??
     242             :                 12.0,
     243           2 :             showSelectedLabels: widget.showSelectedLabels ??
     244           1 :                 bottomNavBarTheme.showSelectedLabels ??
     245             :                 true,
     246           2 :             showUnselectedLabels: widget.showUnselectedLabels ??
     247           1 :                 bottomNavBarTheme.showUnselectedLabels ??
     248             :                 true,
     249           2 :             selectedIconTheme: widget.selectedIconTheme ??
     250           1 :                 bottomNavBarTheme.selectedIconTheme ??
     251             :                 const IconThemeData(size: 24.0),
     252           2 :             unselectedIconTheme: widget.unselectedIconTheme ??
     253           1 :                 bottomNavBarTheme.unselectedIconTheme ??
     254             :                 const IconThemeData(size: 20.0),
     255           4 :             items: widget.items.map((item) {
     256           1 :               return BottomNavigationBarItem(
     257           1 :                 icon: Container(
     258           2 :                   padding: widget.itemPadding ?? EdgeInsets.zero,
     259             :                   alignment: Alignment.center,
     260           1 :                   child: item.icon,
     261             :                 ),
     262           1 :                 label: item.label,
     263             :               );
     264           1 :             }).toList(),
     265           1 :             currentIndex: _selectedIndex,
     266           1 :             onTap: _onItemTapped,
     267             :           ),
     268             :         ),
     269             :       ),
     270             :     );
     271             :   }
     272             : }

Generated by: LCOV version 1.14