Getx: Get or GetX with BottomNavigationBar

Created on 27 Jun 2020  路  8Comments  路  Source: jonataslaw/getx

Please,
I'm beginning with Get and my initial problem is to create a BottomNavigationBar. I 'm trying create with Statelwess Widget and using Get for control the indexes. Its happening error when to clock on options.
Is it possible ?
Anyone did it anytime

class ProfileScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GetBuilder<ProfileController>(
        init: ProfileController(),
        builder: (s) => IndexedStack(
          index: s.selectedIndex,
          children: <Widget>[
            Body(),
            Body(),
            Body(),
          ],
        ),
      ),
      bottomNavigationBar: SuperFaBottomNavigationBar(),
    );
  }
}

class SuperFaBottomNavigationBar extends StatelessWidget {
  const SuperFaBottomNavigationBar({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GetBuilder<ProfileController>(
      init: ProfileController(),
      builder: (s) => BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('Inicio'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            title: Text('Pesquisa'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            title: Text('Perfil'),
          ),
        ],
        currentIndex: s.selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: (index) => s.onItemTapped(index),
        /* currentIndex: Get.find<ProfileController>().selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: Get.find<ProfileController>().onItemTapped, */
      ),
    );
  }
}

class ProfileController extends GetController {

  final _selectedIndex = 0.obs;
  set selectedIndex(value) => this._selectedIndex.value = value;
  get selectedIndex => this._selectedIndex.value;

  onItemTapped(int index) {
    this.selectedIndex(index);
    update();
  }
}

Most helpful comment

You made 2 mistakes when creating your model, one was to try to access a set as if it were a method, and another was to initialize the same controller 2 times. Here is an example of your code working:

class ProfileScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GetBuilder<ProfileController>(
        init: ProfileController(),
        builder: (s) => IndexedStack(
          index: s.selectedIndex,
          children: <Widget>[
            Center(
              child: Text(s._selectedIndex.string),
            ),
            Center(
              child: Text(s._selectedIndex.string),
            ),
            Center(
              child: Text(s._selectedIndex.string),
            ),
          ],
        ),
      ),
      bottomNavigationBar: SuperFaBottomNavigationBar(),
    );
  }
}

class SuperFaBottomNavigationBar extends StatelessWidget {
  const SuperFaBottomNavigationBar({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GetBuilder<ProfileController>( // init only first time
      builder: (s) => BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('Inicio'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            title: Text('Pesquisa'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            title: Text('Perfil'),
          ),
        ],
        currentIndex: s.selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: (index) => s.onItemTapped(index),
        /* currentIndex: Get.find<ProfileController>().selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: Get.find<ProfileController>().onItemTapped, */
      ),
    );
  }
}

class ProfileController extends GetxController {
  final _selectedIndex = 0.obs;
  set selectedIndex(value) => this._selectedIndex.value = value;
  get selectedIndex => this._selectedIndex.value;

  onItemTapped(int index) {
    this.selectedIndex = index; // The set method is accessed this way, you have confused it with methods.
    update();
  }
}

All 8 comments

Hi, you can't put init twice. Why are you putting a GetBuilder in the bottomBar?
You just need to wrap indexedStack in a GetBuilder, and that's it.

I guess this do exactly what you want

class BottomNavigationPageController extends GetxController {
  static BottomNavigationPageController get to => Get.find();

  final currentIndex = 0.obs;

  List<Widget> pages = [
    Tab1(),
    Tab2(),
    Tab3(),
  ];

  Widget get currentPage => pages[currentIndex.value];

  void changePage(int _index) {
    currentIndex.value = _index;
  }
}
class BottomNavigationPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return obx(
      () => Scaffold(
        body: BottomNavigationPageController.to.currentPage,
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: BottomNavigationPageController.to.currentIndex.value,
          onTap: BottomNavigationPageController.to.changePage,
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Container(),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Container(),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Container(),
            ),
          ],
        ),
      ),
    );
  }
}

Hijacking this a little, but how would you add transition effects and/or router to BottomNavigationBar?

Hijacking this a little, but how would you add transition effects and/or router to BottomNavigationBar?

you say transition between tabs or each tab having multiple pages? for the second case you can use nested navigation. for transition between tabs on bottomNavibationBar I guess you can't add a transition effect.

Transition animations between tabs on BottomNavigationBar. Or implementing routing instead of programmatic thisPage[isIndex] type of solution. It's not only transition animations that are missing with BottomNavigationBar, but also Android back button handling. Routing would solve a lot of that. Was wondering if there's an elegant solution to that with Get.

I searched a lot and found no way to do tabs navigation as routes. For android back button, which action do you want? if is for trancking the tabs like a stack you can do exactly that, save the index on a stack every time change tab, and poping it when press the back button, but i guess this is not a good aproach.

You made 2 mistakes when creating your model, one was to try to access a set as if it were a method, and another was to initialize the same controller 2 times. Here is an example of your code working:

class ProfileScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GetBuilder<ProfileController>(
        init: ProfileController(),
        builder: (s) => IndexedStack(
          index: s.selectedIndex,
          children: <Widget>[
            Center(
              child: Text(s._selectedIndex.string),
            ),
            Center(
              child: Text(s._selectedIndex.string),
            ),
            Center(
              child: Text(s._selectedIndex.string),
            ),
          ],
        ),
      ),
      bottomNavigationBar: SuperFaBottomNavigationBar(),
    );
  }
}

class SuperFaBottomNavigationBar extends StatelessWidget {
  const SuperFaBottomNavigationBar({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GetBuilder<ProfileController>( // init only first time
      builder: (s) => BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('Inicio'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            title: Text('Pesquisa'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            title: Text('Perfil'),
          ),
        ],
        currentIndex: s.selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: (index) => s.onItemTapped(index),
        /* currentIndex: Get.find<ProfileController>().selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: Get.find<ProfileController>().onItemTapped, */
      ),
    );
  }
}

class ProfileController extends GetxController {
  final _selectedIndex = 0.obs;
  set selectedIndex(value) => this._selectedIndex.value = value;
  get selectedIndex => this._selectedIndex.value;

  onItemTapped(int index) {
    this.selectedIndex = index; // The set method is accessed this way, you have confused it with methods.
    update();
  }
}

Well, as it was misuse, and I presented the corrected and compile example, I am closing this. If you encounter a problem with Get, you can open another issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ChiwanAhn picture ChiwanAhn  路  4Comments

omartinma picture omartinma  路  3Comments

aztecrabbit picture aztecrabbit  路  3Comments

jemariads picture jemariads  路  4Comments

manojeeva picture manojeeva  路  3Comments