0

I'm new to flutter, trying to implement BottomNavigationBar in a demo app. Bottom bar does show in app but can't change the current item on tapping, neither does the screen changes.

I've tried various methods to load screens but seems like the onTap function is not getting called.

Here is my code.

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {

    final Size screenSize = MediaQuery.of(context).size;

    int _currentTab = 0;

    Widget body() {
      switch (_currentTab) {
        case 0:
          return FeedScreen();
        case 1:
          return SearchScreen();
        case 2:
          return ProfileScreen();
        default:
          return FeedScreen();
      }
    }

    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        onTap: (newValue) {
          setState(() {
            _currentTab = newValue;
          });
        },
        currentIndex: _currentTab,
        items: [
          BottomNavigationBarItem(
            icon: ImageIcon(
              AssetImage('images/home.png'),
            ),
            title: SizedBox.shrink(),
          ),
          BottomNavigationBarItem(
            icon: ImageIcon(
              AssetImage('images/search.png'),
            ),
            title: SizedBox.shrink(),
          ),
          BottomNavigationBarItem(
            icon: CircleAvatar(
              radius: 15,
              backgroundImage: AssetImage('images/avatar.png'),
            ),
            title: SizedBox.shrink(),
          )
        ],
      ),
      appBar: PreferredSize(
        preferredSize: Size(screenSize.width, 50.0),
        child: CustomAppBar(),
      ),
      body: body(),
    );
  }
}
Raj D
  • 205
  • 3
  • 16

3 Answers3

3

your int _currentTab = 0; is inside build method. put it outside.

everytime you trigger the setState, _currentTab will always be equal to 0 which is the FeedScreen because the variable is inside the build method

MJ Montes
  • 3,234
  • 1
  • 19
  • 21
  • 2
    Build method called everytime when the state changes, so it always be 0 in your case, but while adding outside, then it will persist the value, As your Widget still on the screen – Jitesh Mohite Aug 25 '20 at 11:41
1

Try the below code!

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {

 int _currentTab = 0;

  @override
  Widget build(BuildContext context) {

    final Size screenSize = MediaQuery.of(context).size;

    Widget body() {
      switch (_currentTab) {
        case 0:
          return FeedScreen();
        case 1:
          return SearchScreen();
        case 2:
          return ProfileScreen();
        default:
          return FeedScreen();
      }
    }

    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        onTap: (newValue) {
          setState(() {
            _currentTab = newValue;
          });
        },
        currentIndex: _currentTab,
        items: [
          BottomNavigationBarItem(
            icon: ImageIcon(
              AssetImage('images/home.png'),
            ),
            title: SizedBox.shrink(),
          ),
          BottomNavigationBarItem(
            icon: ImageIcon(
              AssetImage('images/search.png'),
            ),
            title: SizedBox.shrink(),
          ),
          BottomNavigationBarItem(
            icon: CircleAvatar(
              radius: 15,
              backgroundImage: AssetImage('images/avatar.png'),
            ),
            title: SizedBox.shrink(),
          )
        ],
      ),
      appBar: PreferredSize(
        preferredSize: Size(screenSize.width, 50.0),
        child: CustomAppBar(),
      ),
      body: body(),
    );
  }
}

write int _currentTab = 0 in outside of build method, because when you update newValue into _currentTab also setState reassign 0 value.

Rohit Soni
  • 1,300
  • 6
  • 12
0

Just to add a piece of information regarding the issue:

I have used this part of code:

Widget body() {
  switch (_currentTab) {
    case 0:
      return FeedScreen(0);
    case 1:
      return FeedScreen(1);
    case 2:
      return FeedScreen(2);
    default:
      return FeedScreen();
  }
}

As I have a parameter to decide whether I show a part of the screen or not. However it DOES NOT WORK, I do not know why. So I had to create different class for each situation.

Widget body() {
  switch (_currentTab) {
    case 0:
      return Class1(0);
    case 1:
      return Class2(1);
    case 2:
      return Class3(2);
    default:
      return Class4();
  }
}

Inside each Class* I am able to call FeedScreen(n), with parameters. Otherwise the setState does not understand that something changed. It seems wierd , but happend. If someone has any trick to avoid it , please let me know.