I have a list of blog posts in the body and bottom navigation bar. I want to hide bottom navigation bar with a slide down animation when the posts list is scrolled down and visible with a slide up animation when scrolled up. How to do it?
Try to wrap the ListView as the child of a NotificationListener and listen to scrolling events https://docs.flutter.io/flutter/widgets/OverscrollNotification-class.html
other approach is using ScrollUpdateNotification https://docs.flutter.io/flutter/widgets/ScrollUpdateNotification-class.html
I was able to do it in my application using Provider. This is how I proceeded:
1- Create your provider class, that will have to method to switch the visibility of your bottom bar and notify the listeners:
class BottomBarVisibilityProvider extends ChangeNotifier {
bool isVisible = true;
void show() {
if (!isVisible) {
isVisible = true;
notifyListeners();
}
}
void hide() {
if (isVisible) {
isVisible = false;
notifyListeners();
}
}
}
2- add a consumer of this class on top of your bottom bar, the AnimatedContainer will consume the visibility status from your provider and set if you want to display the bottomBar or not depending on the scroll direction of your scrollable widget:
bottomNavigationBar: Consumer<BottomBarVisibilityProvider>(
builder: (context, bottomBarVisibilityProvider, child) =>
AnimatedContainer(
duration: const Duration(milliseconds: 200),
child: bottomBarVisibilityProvider.isVisible
? Wrap(
children: const [BottomBar()],
)
: Wrap(),
),
),
3- Another consumer now, but for the scrollable widget: and note that in this widget your need to add a listener for your scrollController so your could change the visibility status in your provider depending on the user scroll direction:
return Consumer<BottomBarVisibilityProvider>(
builder: (context, bottomBarVisibilityProvider, child) {
scrollController.addListener(() {
final direction =
scrollController.position.userScrollDirection;
if (direction == ScrollDirection.forward) {
if (!bottomBarVisibilityProvider.isVisible) {
bottomBarVisibilityProvider.show();
}
} else if (direction == ScrollDirection.reverse) {
if (bottomBarVisibilityProvider.isVisible) {
bottomBarVisibilityProvider.hide();
}
}
});
return ListView.builder(
key: eventListKey,
controller: scrollController,
itemCount: snapshot.docs.length,
itemBuilder: (context, index) {
return TravelCard(events.elementAt(index));
},
);
},
);
Happy fluttering!
My team has a package called: hidable. Which basically makes it easy to add scroll-to-hide functionality to any static-located widget.
Depend on it:
dependencies:
hidable: ^1.0.2
Create a scroll controller, inside your widget state:
final ScrollController scrollController = ScrollController();
Pass that scrollController
to your scrollable widget - (ListView, SingleChildScrollView and etc.)
ListView(
controller: scrollController,
...
)
Then wrap your BottomNavigationBar
with the Hidable
widget:
Hidable(
controller: scrollController,
wOpacity: true, // As default it's true.
size: 56, // As default it's 56.
child: BottomNavigationBar(...),
)
You need a ScrollController to monitor/observe the scroll direction of the Listview. The controller will be initialized in the initState and a listener should be added to it....The listener should toggle a boolean depending on the Scroll direction....Then the Bottom Naigatio Bar should be wrapped with an OffStage
This code should help
import 'package:flutter/material.dart';
import 'package:flutter/rendering.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,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isVisible = true;
ScrollController controller;
@override
void initState() {
super.initState();
controller = ScrollController();
controller.addListener(() {
setState(() {
_isVisible = controller.position.userScrollDirection == ScrollDirection.forward;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
controller: controller,
children: List.generate(200, (index) => Text(("$index"))),
),
bottomNavigationBar: Offstage(
offstage: !_isVisible,
child: BottomNavigationBar(
items: [
BottomNavigationBarItem(
title: Text("Hello"),
icon: Icon(Icons.style)
),
BottomNavigationBarItem(
title: Text("Hi"),
icon: Icon(Icons.style)
),
BottomNavigationBarItem(
title: Text("Hey"),
icon: Icon(Icons.style)
)
],
),
),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With