I am currently using persistent_bottom_nav_bar: 6.2.1
and trying to use OpenContainer
to navigate between screens with animation. However, the problem is that when I use PersistentTabView
as the main screen's body, both the AppBar and BottomNavigationBar are still visible when navigating to the new screen.
Here is my code:
class _DashboardView extends State<UserDashboardScreen> {
final AuthLocal _authLocal = AuthLocal();
late PersistentTabController _controller;
final ScrollController _scrollControllerHome = ScrollController();
final ScrollController _scrollControllerShop = ScrollController();
@override
void initState() {
super.initState();
_controller = PersistentTabController(initialIndex: 0);
}
List<Widget> _buildScreens() {
return [
HomeScreen(scrollController: _scrollControllerHome),
WishlistScreen(scrollController: _scrollControllerShop),
];
}
Future<void> _handleLogout() async {
await _authLocal.clearAuthData();
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => LoginScreen()), (route) => false);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: DynamicAppBar(
backgroundColor: ColorConstant.secondary,
title: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(AssetConstant.appLogo, width: 30),
const SizedBox(width: 8),
Text("GEBOK", style: TextStyle(color: ColorConstant.primary, fontWeight: FontWeight.bold, fontSize: 18)),
],
),
trailingWidgets: [
OpenContainer(
transitionType: ContainerTransitionType.fadeThrough,
transitionDuration: Duration(milliseconds: 600),
closedElevation: 0,
closedShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
closedBuilder: (context, openContainer) {
return IconButton(
icon: const Icon(Icons.search, color: ColorConstant.gray),
onPressed: () {
PersistentNavBarNavigator.pushNewScreen(
context,
screen: SearchScreen(),
withNavBar: false,
pageTransitionAnimation: PageTransitionAnimation.cupertino,
);
},
);
},
openBuilder: (context, _) => Container(),
),
PopupMenuButton<String>(
offset: Offset(0, 60),
color: ColorConstant.secondary,
tooltip: "Menu",
onSelected: (val) async {
if (val == "logout") {
_handleLogout();
} else if (val == "info") {
Navigator.push(
context,
PageTransition(
type: PageTransitionType.rightToLeft,
duration: Duration(milliseconds: 500),
child: InfoAppScreen(),
),
);
}
},
itemBuilder:
(BuildContext context) => <PopupMenuEntry<String>>[
const PopupMenuItem<String>(
value: 'logout',
child: Row(children: [Icon(Icons.exit_to_app_outlined), SizedBox(width: 4), Text('Logout')]),
),
const PopupMenuItem<String>(
value: 'info',
child: Row(children: [Icon(Icons.info_outline), SizedBox(width: 4), Text('Info App')]),
),
],
),
],
),
body: PersistentTabView(
context,
controller: _controller,
screens: _buildScreens(),
items: _navBarsItems(),
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: true,
// This needs to be true if you want to move up the screen on a non-scrollable screen when keyboard appears. Default is true.
stateManagement: true,
// Default is true.
hideNavigationBarWhenKeyboardAppears: true,
// popBehaviorOnSelectedNavBarItemPress: PopActionScreensType.all,
padding: const EdgeInsets.only(top: 8),
backgroundColor: ColorConstant.secondary,
isVisible: true,
animationSettings: const NavBarAnimationSettings(
navBarItemAnimation: ItemAnimationSettings(
// Navigation Bar's items animation properties.
duration: Duration(milliseconds: 400),
curve: Curves.ease,
),
screenTransitionAnimation: ScreenTransitionAnimationSettings(
// Screen transition animation on change of selected tab.
animateTabTransition: true,
duration: Duration(milliseconds: 200),
screenTransitionAnimationType: ScreenTransitionAnimationType.fadeIn,
),
),
confineToSafeArea: true,
navBarHeight: kBottomNavigationBarHeight,
navBarStyle: NavBarStyle.style3,
),
);
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: Icon(CupertinoIcons.home),
title: ("Home"),
activeColorPrimary: CupertinoColors.activeBlue,
inactiveColorPrimary: CupertinoColors.systemGrey,
scrollController: _scrollControllerHome,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.bookmarks_outlined),
title: ("Wishlist"),
activeColorPrimary: CupertinoColors.activeBlue,
inactiveColorPrimary: CupertinoColors.systemGrey,
scrollController: _scrollControllerShop,
),
];
}
}
And this my code to navigate with OpenContainer
:
OpenContainer(
transitionType: ContainerTransitionType.fadeThrough,
transitionDuration: const Duration(milliseconds: 500),
openBuilder: (context, _) => BookDetailScreen(bookId: item.id),
closedElevation: 0,
closedColor: Colors.transparent,
closedShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
closedBuilder: (context, openContainer) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: openContainer,
borderRadius: BorderRadius.circular(8),
child: <my content>,
),
);
},
),
I had an idea to combine them in the InkWell
's onTap
like this:
onTap: () {
openContainer();
Future.delayed(const Duration(milliseconds: 300), () {
PersistentNavBarNavigator.pushNewScreen(
context,
screen: BookDetailScreen(bookId: item.id),
withNavBar: false,
pageTransitionAnimation: PageTransitionAnimation.cupertino,
);
});
}
But the result is that it pushes the screen twice — first with openContainer() and then with pushNewScreen(). The first time, the bottom and app bars are hidden as expected, but on the next navigation, they appear again. I also don’t want to push two screens at once when navigating.
How can I solve this properly? Detail code on my repo: https://github.com/gioVerdiansyah/Flutter-Issue
To achieve the desired OpenContainer
animation while also hiding the AppBar
and BottomNavigationBar
from the HomeScreen, you need to tell the OpenContainer to use the root navigator. This will ensure the TestingScreen is pushed on top of everything, including the current screen's Scaffold elements.
You can do this by setting the useRootNavigator
property of the OpenContainer
to true
.