PersistentBottomNavBar icon indicating copy to clipboard operation
PersistentBottomNavBar copied to clipboard

All pages rebuild when we click on any menu in PersistentTabView.custom

Open ketancts opened this issue 3 years ago • 3 comments

I am using PersistentTabView.custom with customWidget. When I click on any bottom navigation tab all build methods are executed. How to prevent for rebuilding all pages? I just want that only selected page (menu) build executes

Here is my code

screen_main.dart

`class ScreenMain extends StatefulWidget {
  const ScreenMain({Key? key}) : super(key: key);

  @override
  State<ScreenMain> createState() => _ScreenMainState();
}

class _ScreenMainState extends State<ScreenMain> {
  final PersistentTabController _controller =
      PersistentTabController(initialIndex: 0);

  @override
  Widget build(BuildContext context) {
    List<Widget> _buildScreens() {
      return [
        const ScreenTabPortfolio(),
        const ScreenTabWallet(),
        const ScreenTabPlanner(),
        const ScreenTabLeader(),
        const ScreenTabMenu(),
      ];
    }

    List<PersistentBottomNavBarItem> _navBarsItems() {
      return [
        PersistentBottomNavBarItem(
          icon: Image.asset(
            AppIcons.icPortfolio,
            width: 24,
            height: 24,
            color: _controller.index == 0
                ? Colors.white
                : AppColors.bottomNavIconColor,
          ),
          title: AppStrings.strPortfolio,
        ),
        PersistentBottomNavBarItem(
          icon: Image.asset(
            AppIcons.icWallet,
            width: 24,
            height: 24,
            color: _controller.index == 1
                ? Colors.white
                : AppColors.bottomNavIconColor,
          ),
          title: AppStrings.strWallet,
        ),
        PersistentBottomNavBarItem(
          icon: Image.asset(
            AppIcons.icPlanner,
            width: 24,
            height: 24,
            color: _controller.index == 2
                ? Colors.white
                : AppColors.bottomNavIconColor,
          ),
          title: AppStrings.strPlanner,
        ),
        PersistentBottomNavBarItem(
          icon: Image.asset(
            AppIcons.icLeader,
            width: 24,
            height: 24,
            color: _controller.index == 3
                ? Colors.white
                : AppColors.bottomNavIconColor,
          ),
          title: AppStrings.strLeader,
        ),
        PersistentBottomNavBarItem(
          icon: Image.asset(
            AppIcons.icMore,
            width: 24,
            height: 24,
            color: _controller.index == 4
                ? Colors.white
                : AppColors.bottomNavIconColor,
          ),
          title: AppStrings.strMore,
        ),
      ];
    }

    return Scaffold(
      body: WillPopScope(
        onWillPop: () async {
          if (_controller.index == 0) {
            final value = await showDialog<bool>(
              context: context,
              builder: (context) {
                return AdaptiveDialog(
                  AppStrings.strMessageExitApp,
                  AppStrings.strNo,
                  AppStrings.strYes,
                  () {
                    Navigator.of(context).pop(false);
                  },
                  () {
                    Navigator.of(context).pop(true);
                  },
                  title: AppStrings.strAreYouSure,
                );
              },
            );
            return value == true;
          } else {
            setState(() {
              _controller.index = 0;
            });
            return await Future(() => false);
          }
        },
        child: PersistentTabView.custom(
          context,
          controller: _controller,
          screens: _buildScreens(),
          itemCount: _buildScreens().length,
          confineInSafeArea: true,
          backgroundColor: AppColors.getThemeColor('backgroundColor'),
          handleAndroidBackButtonPress: true,
          resizeToAvoidBottomInset: true,
          stateManagement: false,
          hideNavigationBarWhenKeyboardShows: true,
          screenTransitionAnimation: const ScreenTransitionAnimation(
            animateTabTransition: true,
            curve: Curves.ease,
            duration: Duration(milliseconds: 200),
          ),
          customWidget: WidgetCustomNavBar(
            items: _navBarsItems(),
            selectedIndex: _controller.index,
            onItemSelected: (index) {
              setState(() {
                _controller.index = index;
              });
            },
          ),
        ),
      ),
    );
  }
}
`

widget_custom_navbar.dart

`class WidgetCustomNavBar extends StatelessWidget {
  final int? selectedIndex;
  final List<PersistentBottomNavBarItem>? items;
  final ValueChanged<int>? onItemSelected;

  const WidgetCustomNavBar({
    Key? key,
    this.selectedIndex,
    @required this.items,
    this.onItemSelected,
  }) : super(key: key);

  Widget _buildItem(PersistentBottomNavBarItem item, bool isSelected) {
    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 0.0, vertical: 5.0),
      alignment: Alignment.center,
      height: kToolbarHeight,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          isSelected
              ? Container(
                  constraints: const BoxConstraints(minWidth: 100),
                  padding: const EdgeInsets.symmetric(horizontal: 5),
                  height: kToolbarHeight,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: AssetImage(AppIcons.icSelectedMenu),
                      fit: BoxFit.fill,
                    ),
                  ),
                  child: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      const SizedBox(width: 5),
                      IconTheme(
                        data: const IconThemeData(
                          size: 24.0,
                          color: Colors.white,
                        ),
                        child: item.icon,
                      ),
                      const SizedBox(width: 5),
                      Material(
                        type: MaterialType.transparency,
                        child: FittedBox(
                          child: Text(
                            item.title!,
                            style: const TextStyle(
                              fontSize: 13,
                              color: Colors.white,
                              fontWeight: FontWeight.w400,
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                )
              : Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 10.0),
                  child: IconTheme(
                    data: const IconThemeData(size: 26.0),
                    child: item.icon,
                  ),
                ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.zero,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.only(
          topLeft: Radius.circular(22),
          topRight: Radius.circular(22),
        ),
      ),
      elevation: 10.0,
      child: Container(
        decoration: BoxDecoration(
          color: AppColors.getThemeColor('cardBgColor'),
          borderRadius: const BorderRadius.only(
            topLeft: Radius.circular(20),
            topRight: Radius.circular(20),
          ),
        ),
        width: MediaQuery.of(context).size.width,
        height: kToolbarHeight,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: items!.map((item) {
            int index = items!.indexOf(item);
            return InkWell(
              onTap: () {
                onItemSelected!(index);
              },
              child: _buildItem(item, selectedIndex == index),
            );
          }).toList(),
        ),
      ),
    );
  }
}
`

ketancts avatar Dec 31 '21 10:12 ketancts

Hi @ketancts I have the same case like yours, did you find any solution ?

wahyu-handayani avatar Jan 10 '22 06:01 wahyu-handayani

@wahyu-handayani: No, I didn't find any solution yet.

ketancts avatar Jan 10 '22 09:01 ketancts

I think it's because you're defining and calling your _buildScreens() and other functions inside the build method of the widget, causing all of them to be rebuilt whenever the state changes. You should move these out of the build method.

alguintu avatar Mar 18 '22 05:03 alguintu