What is the alternative of using setState() in flutter?

Issue

I am implementing Curved_Navigation_Bar in my Flutter poject and I am not using any class(i.e. Stateful / Stateless). I want to change the state of the icons that are in my curved_navigation_bar, means I want that animation effect on my navigation bar. Because the respective pages of those icons are navigating but not those items. No matter on which icon I click, it is still showing that first icon only. The animation/interpolation of icons is not happening.

As I am not using any Stateful/Stateless class, so I am not using Scaffold. Inside Scaffold we can change the state of the current object using setState(() { }).

So how can I change the state of my navigation bar?

Here is my code below:

navigation_bar.dart

import 'package:flutter/material.dart';
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
import 'package:thehelpdesk/components/home/history.dart';
import 'package:thehelpdesk/components/home/home.dart';
import 'package:thehelpdesk/components/home/menu.dart';
import 'package:thehelpdesk/components/home/notification.dart';
import 'package:thehelpdesk/components/home/person.dart';

int currentIndex = 0 ;
Widget navBarSection(Color color, Color btnColor, BuildContext context) {
  return CurvedNavigationBar(
      index: 0,
      items:
      [
        Icon(Icons.home, color: Colors.white),
        Icon(Icons.notifications, color: Colors.white),
        Icon(Icons.menu, color: Colors.white),
        Icon(Icons.history, color: Colors.white),
        Icon(Icons.person, color: Colors.white),
      ],
      color: color,
      buttonBackgroundColor: btnColor,
      animationCurve: Curves.easeInCubic,
      animationDuration: Duration(milliseconds: 600),
onTap: (index) {
if(currentIndex == 0){
          Navigator.of(context).push(MaterialPageRoute(builder: (context) => HomePage()));
          currentIndex = index ;
        }
        if(currentIndex == 1){
          Navigator.of(context).push(MaterialPageRoute(builder: (context) => NotificationPage()));
          currentIndex = index ;
        }
        if(currentIndex == 2){
          Navigator.of(context).push(MaterialPageRoute(builder: (context) => MenuPage()));
          currentIndex = index ;
        }
        if(currentIndex == 3){
          Navigator.of(context).push(MaterialPageRoute(builder: (context) => HistoryPage()));
          currentIndex = index ;
        }
        if(currentIndex == 4){
          Navigator.of(context).push(MaterialPageRoute(builder: (context) => PersonPage()));
          currentIndex = index ;
        }
      }
  );

One of the pages I want to navigate on tapping a icon:

home.dart

import 'package:flutter/material.dart';
import 'package:thehelpdesk/widgets/appbar.dart';
import 'package:thehelpdesk/widgets/navigation_bar.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: aapBarSection('Home', Colors.blueAccent[700], context),
        bottomNavigationBar: navBarSection(
          Colors.blueAccent[700],
          Colors.blueAccent[700],
          context
        ),
    );
  }
}

Another page on tapping the 2nd icon:

notification.dart

import 'package:flutter/material.dart';
import 'package:thehelpdesk/widgets/appbar.dart';
import 'package:thehelpdesk/widgets/navigation_bar.dart';

class NotificationPage extends StatefulWidget {
  @override
  _NotificationPageState createState() => _NotificationPageState();
}

class _NotificationPageState extends State<NotificationPage> {

  final message = [
    'Hi Xyz,your invoice for It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.',
    'Hi Xyz, Agility Rehab Care wishing you a very happy birthday! for It has survived not only five centuries, but also the leap remaining essentially unchanged.',
    'Hi Xyz, From our Agility Rehab Care you are being reminded that you have an appointment with us on this Friday.',
    'Hi Xyz, This is a reminder for you from Agility Rehab Care It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.',
  ];

  final images = [
    'assets/images/Invoice.png',
    'assets/images/cake.png',
    'assets/images/calender.png',
    'assets/images/Reminder.png'
  ];
  String date = '22/02/2021';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: aapBarSection('Notification',Colors.blueAccent[700],context),
      bottomNavigationBar: navBarSection(
        Colors.blueAccent[700],
        Colors.blueAccent[700],
        context
      ),
      body: ListView.builder(
          itemCount: message.length,
          itemBuilder: (context, index) {
            return Padding(
              padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
              child: SizedBox(
                height: 200,
                child: Card(
                    elevation: 5.0,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10.0),
                    ),
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Container(
                        child: Column(
                          children: [
                            Flexible(
                              flex: 7,
                              child: Container(
                                child: Row(
                                  children: [
                                    Expanded(
                                      flex: 2,
                                      child: Container(
                                        decoration: BoxDecoration(
                                            image: DecorationImage(
                                                image: AssetImage(
                                                    images[index]))),
                                      ),
                                    ),
                                    Expanded(
                                      flex: 8,
                                      child: Container(
                                        child: Text(message[index]),
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                            ),
                            Flexible(
                              flex: 3,
                              child: Padding(
                                padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
                                child: Container(
                                  child: Row(
                                    mainAxisAlignment: MainAxisAlignment.end,
                                    children: [Text(date)],
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    )),
              ),
            );
          })
    );
  }
}

Solution

The short answer is that just add currentIndex as one of the parameter inside your navBarSection.

navigation_bar.dart

Widget navBarSection(
  int currentIndex,
  Color color,
  Color btnColor,
  BuildContext context,
) {
  return CurvedNavigationBar(
      index: currentIndex,
      items: [
        Icon(Icons.home, color: Colors.white),
        Icon(Icons.notifications, color: Colors.white),
        Icon(Icons.menu, color: Colors.white),
        Icon(Icons.history, color: Colors.white),
        Icon(Icons.person, color: Colors.white),
      ],
      color: color,
      buttonBackgroundColor: btnColor,
      animationCurve: Curves.easeInCubic,
      animationDuration: Duration(milliseconds: 600),
      onTap: (index) {
        if (currentIndex == 0) {
          Navigator.of(context)
              .push(MaterialPageRoute(builder: (context) => HomePage()));
          currentIndex = index;
        }
        if (currentIndex == 1) {
          Navigator.of(context).push(
              MaterialPageRoute(builder: (context) => NotificationPage()));
          currentIndex = index;
        }
        if (currentIndex == 2) {
          Navigator.of(context)
              .push(MaterialPageRoute(builder: (context) => MenuPage()));
          currentIndex = index;
        }
        if (currentIndex == 3) {
          Navigator.of(context)
              .push(MaterialPageRoute(builder: (context) => HistoryPage()));
          currentIndex = index;
        }
        if (currentIndex == 4) {
          Navigator.of(context)
              .push(MaterialPageRoute(builder: (context) => PersonPage()));
          currentIndex = index;
        }
      });
}

Inside home.dart, just pass the currentIndex of the page.

home.dart

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: aapBarSection('Home', Colors.blueAccent[700], context),
      bottomNavigationBar: navBarSection(
        0,
        Colors.blueAccent[700],
        Colors.blueAccent[700],
        context,
      ),
    );
  }
}

This should solve your problem but as you can see, this is not the best way to implement the bottomnavigationbar and widget due to:

  1. You will lose the animation that the package provided.
  2. It does not comply with the bottom navigation behavior since it will navigate to a new page instead of replacing it.

Lose animation

To solve this, create a new stateful widget,as for this example, I called it main_page.dart.

main_page.dart

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _currentIndex = 0;
  List<Widget> _pages = [
    HomePage(),
    NotificationPage(),
    MenuPage(),
    HistoryPage(),
    PersonPage(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages.elementAt(_currentIndex),
      bottomNavigationBar: CurvedNavigationBar(
        backgroundColor: Colors.blueAccent,
        items: [
          Icon(Icons.home, color: Colors.white),
          Icon(Icons.notifications, color: Colors.white),
          Icon(Icons.menu, color: Colors.white),
          Icon(Icons.history, color: Colors.white),
          Icon(Icons.person, color: Colors.white),
        ],
        color: Colors.blueAccent[700],
        buttonBackgroundColor: Colors.blueAccent[700],
        animationCurve: Curves.easeInCubic,
        animationDuration: Duration(milliseconds: 600),
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
      ),
    );
  }
}

Called the the main_page.dart inside your main.dart.

main.dart

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MainPage(),
    );
  }
}

lastly, remove any bottomNavigationBar from home,history,menu,notification,and person page.

The result is

Smooth animation

Answered By – Hafiz Mokhtar

Answer Checked By – Pedro (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.