How to change icon on TabItem on currentTab

360 views Asked by At

I have a BottomNavigationBar which works perfectly with color change on active and inactive but I don't want to change color but change icons on active and inactive with SVG image. Below is my code:

class AppNavigation extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => AppState();
}

const assetHome = 'assets/home_off.svg';
const assetRedemptions = 'assets/redeemed_off.svg';
const assetProfile = 'assets/profile_off.svg';


const assetHome1 = 'assets/home_on.svg';
const assetRedemptions1 = 'assets/redeemed_on.svg';
const assetProfile1 = 'assets/profile_on.svg';


class AppState extends State<AppNavigation> {
 
  static int currentTab = 0;

 // list tabs here
  final List<TabItem> tabs = [
    TabItem(
      tabName: "Home",
      icon: Icons.home,
      page: MyDealApp(),
    ),
    TabItem(
      tabName: "Announcement",
      icon: Icons.announcement,
      page: MyRedemptionApp(),
    ),
    TabItem(
      tabName: "Notification",
      icon: Icons.notifications,
      page: MyProfileApp(),
    ),
  ];

  AppState() {
    tabs.asMap().forEach((index, details) {
      details.setIndex(index);
    });
  }

  void _selectTab(int index) {
    if (index == currentTab) {
      tabs[index].key.currentState.popUntil((route) => route.isFirst);
   
    } else {
      setState(() => currentTab = index);
      debugPrint("currentTabber:$currentTab");
    }
  }

  @override
  Widget build(BuildContext context) {
    // WillPopScope handle android back btn
    return WillPopScope(
      onWillPop: () async {
        final isFirstRouteInCurrentTab =
        !await tabs[currentTab].key.currentState.maybePop();
        if (isFirstRouteInCurrentTab) {
          // if not on the 'main' tab
          if (currentTab != 0) {
            // select 'main' tab
            _selectTab(0);
            // back button handled by app
            return false;
          }
        }
        return isFirstRouteInCurrentTab;
      },
      child: Scaffold(
        // indexed stack shows only one child
        body: IndexedStack(
          index: currentTab,
          children: tabs.map((e) => e.page).toList(),
        ),
        // Bottom navigation
        bottomNavigationBar: BottomNavigation(
          onSelectTab: _selectTab,
          tabs: tabs,
        ),
      ),
    );
  }
}

class TabItem {
  // you can customize what kind of information is needed
  // for each tab
  final String tabName;
  final IconData icon;
  final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
  int _index = 0;
  Widget _page;

  TabItem({
    @required this.tabName,
    @required this.icon,
    @required Widget page,
  }) {
    _page = page;
  }

  void setIndex(int i) {
    _index = i;
  }

  int getIndex() => _index;

  Widget get page {
    return Visibility(
      // only paint this page when currentTab is active
      visible: _index == AppState.currentTab,
      // important to preserve state while switching between tabs
      maintainState: true,
      child: Navigator(
        // key tracks state changes
        key: key,
        onGenerateRoute: (routeSettings) {
          return MaterialPageRoute(
            builder: (_) => _page,
          );
        },
      ),
    );
  }
}

class BottomNavigation extends StatelessWidget {
  BottomNavigation({
    this.onSelectTab,
    this.tabs,
  });

  final ValueChanged<int> onSelectTab;
  final List<TabItem> tabs;

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      items: tabs
          .map(
            (e) => _buildItem(
          index: e.getIndex(),
          icon: e.icon,
          tabName: e.tabName,
        ),
      )
          .toList(),
      onTap: (index) => onSelectTab(
        index,
      ),
    );
  }

  BottomNavigationBarItem _buildItem(
      {int index, IconData icon, String tabName}) {
    return BottomNavigationBarItem(
      icon: Icon(
        icon,
        color: _tabColor(index: index),
      ),
      title: Text(
        tabName,
        style: TextStyle(
          color: _tabColor(index: index),
          fontSize: 12,
        ),
      ),
    );
  }

  Color _tabColor({int index}) {
    return AppState.currentTab == index ? colorGreen : Colors.grey;
  }

 }

As you can see _tabColor switch from color from blue to grey on active and inactive but rather I want a switch in icon with declared SVG images above. assetHome for MyDealApp() when it is active and assetHome1 for MyDealApp() when it is inactive, assetRedemptions for MyRedemptionApp() when it is active and assetRedemptions1 for MyRedemptionApp() when it is inactive and finally assetProfile for MyProfileApp() when it is active and assetProfile1 for MyProfileApp() when it is inactive.

enter image description here

enter image description here

1

There are 1 answers

4
RaSha On

You can use activeIcon and icon parameters of BottomNavigationBarItem. If activeIcon is provided, icon will only be displayed when the item is not selected.

 BottomNavigationBarItem _buildItem(
      {int index, IconData activeIcon, IconData inactiveIcon, String tabName}) {
    return BottomNavigationBarItem(
      activeIcon: Icon(
        activeIcon,
        color: _tabColor(index: index),
      ),
      icon: Icon(
        inactiveIcon,
        color: _tabColor(index: index),
      ),
      title: Text(
        tabName,
        style: TextStyle(
          color: _tabColor(index: index),
          fontSize: 12,
        ),
      ),
    );
  }