PersistentBottomNavBar
PersistentBottomNavBar copied to clipboard
All pages rebuild when we click on any menu in PersistentTabView.custom
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(),
),
),
);
}
}
`
Hi @ketancts I have the same case like yours, did you find any solution ?
@wahyu-handayani: No, I didn't find any solution yet.
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.