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?
-
can you show the code – siva kumar May 15 '18 at 19:03
-
You can take your own example as I told above. – Mohith7548 May 16 '18 at 04:12
7 Answers
This solution is just a workaround to this problem. There may be some detrimental changes.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ScrollController _hideButtonController;
var _isVisible;
@override
initState() {
super.initState();
_isVisible = true;
_hideButtonController = new ScrollController();
_hideButtonController.addListener(() {
if (_hideButtonController.position.userScrollDirection ==
ScrollDirection.reverse) {
if(_isVisible)
setState(() {
_isVisible = false;
print("**** $_isVisible up");
});
}
if (_hideButtonController.position.userScrollDirection ==
ScrollDirection.forward) {
if(!_isVisible)
setState(() {
_isVisible = true;
print("**** $_isVisible down");
});
}
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new CustomScrollView(
controller: _hideButtonController,
shrinkWrap: true,
slivers: <Widget>[
new SliverPadding(
padding: const EdgeInsets.all(20.0),
sliver: new SliverList(
delegate: new SliverChildListDelegate(
<Widget>[
const Text('I\'m dedicating every day to you'),
const Text('Domestic life was never quite my style'),
const Text('When you smile, you knock me out, I fall apart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('I realize I am crazy'),
],
),
),
),
],
)),
bottomNavigationBar: AnimatedContainer(
duration: Duration(milliseconds: 500),
height: _isVisible ? 60.0 : 0.0,
child: _isVisible
? new BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
new BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
new BottomNavigationBarItem(
icon: Icon(Icons.card_giftcard),
title: Text('Offers'),
),
new BottomNavigationBarItem(
icon: Icon(Icons.account_box),
title: Text('Account'),
),
],
currentIndex: 0,
)
: Container(
color: Colors.white,
width: MediaQuery.of(context).size.width,
),
),
);
}
}
Also you can use sliver bar with this :-
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ScrollController _hideButtonController;
var _isVisible;
@override
initState() {
super.initState();
_isVisible = true;
_hideButtonController = new ScrollController();
_hideButtonController.addListener(() {
if (_hideButtonController.position.userScrollDirection ==
ScrollDirection.reverse) {
setState(() {
_isVisible = false;
print("**** $_isVisible up");
});
}
if (_hideButtonController.position.userScrollDirection ==
ScrollDirection.forward) {
setState(() {
_isVisible = true;
print("**** $_isVisible down");
});
}
});
}
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
TextEditingController searchController = new TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomPadding: true,
drawer: Container(),
key: scaffoldKey,
body: NestedScrollView(
controller: _hideButtonController,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
title: Container(
child: Card(
elevation: 3.0,
margin: EdgeInsets.only(top: 10.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(2.0))),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
GestureDetector(
child: Icon(
Icons.sort,
color: Colors.black54,
),
onTap: () {
scaffoldKey.currentState.openDrawer();
},
),
SizedBox(
width: 10.0,
),
Expanded(
child: TextField(
controller: searchController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "What are you looking for?"),
),
),
GestureDetector(
onTap: () {
searchController.clear();
},
child: Icon(
Icons.clear,
color: Colors.black54,
),
),
],
),
),
),
),
elevation: 10.0,
automaticallyImplyLeading: false,
expandedHeight: 70,
floating: true,
snap: true,
)
];
},
body: new ListView(
children: <Widget>[
const Text('I\'m dedicating every day to you'),
const Text('Domestic life was never quite my style'),
const Text('When you smile, you knock me out, I fall apart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('I realize I am crazy'),
const Text('I\'m dedicating every day to you'),
const Text('Domestic life was never quite my style'),
const Text('When you smile, you knock me out, I fall apart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('I realize I am crazy'),
],
),
),
bottomNavigationBar: AnimatedContainer(
duration: Duration(seconds: 1),
height: _isVisible ? 60.0 : 0.0,
child: _isVisible
? AnimatedContainer(
duration: Duration(milliseconds: 200),
height: _isVisible ? 60.0 : 0.0,
child: _isVisible
? new BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
new BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
new BottomNavigationBarItem(
icon: Icon(Icons.card_giftcard),
title: Text('Offers'),
),
new BottomNavigationBarItem(
icon: Icon(Icons.account_box),
title: Text('Account'),
),
],
currentIndex: 0,
)
: Container(
color: Colors.white,
width: MediaQuery.of(context).size.width,
),
)
: Container(
color: Theme.of(context).primaryColor,
width: MediaQuery.of(context).size.width,
),
),
// _isVisible
// ? bottomNavigationBar()
// : Container(
// height: 0.0,
// width: MediaQuery.of(context).size.width,
// ),
);
}
}
Kindly comment your view on this codes so we can improve this code.
this was taken from this answer :- Flutter - Hiding FloatingActionButton

- 5,513
- 2
- 27
- 29

- 625
- 3
- 8
- 23
-
-
3Tried this and unfortunately results in "A RenderFlex overflowed by 39 pixels on the bottom." when scrolling. – jwehrle Aug 22 '19 at 21:23
-
1It worked but it has scrolling glitch, the scrolling is not smooth. – Nabin Dhakal Nov 08 '20 at 10:46
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

- 19,761
- 18
- 67
- 116
Screenshot (Null safe):
Code:
The widget used is StatelessWidget
, so don't have to worry about multiple setState
calls.
Create this class:
class ScrollListener extends ChangeNotifier {
double bottom = 0;
double _last = 0;
ScrollListener.initialise(ScrollController controller, [double height = 56]) {
controller.addListener(() {
final current = controller.offset;
bottom += _last - current;
if (bottom <= -height) bottom = -height;
if (bottom >= 0) bottom = 0;
_last = current;
if (bottom <= 0 && bottom >= -height) notifyListeners();
});
}
}
Usage:
class MyPage extends StatelessWidget {
final ScrollController _controller = ScrollController();
final double _bottomNavBarHeight = 56;
late final ScrollListener _model;
MyPage() {
_model = ScrollListener.initialise(_controller);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedBuilder(
animation: _model,
builder: (context, child) {
return Stack(
children: [
ListView.builder(
controller: _controller,
itemCount: 20,
itemBuilder: (_, i) => ListTile(title: Text('Item $i')),
),
Positioned(
left: 0,
right: 0,
bottom: _model.bottom,
child: _bottomNavBar,
),
],
);
},
),
);
}
Widget get _bottomNavBar {
return SizedBox(
height: _bottomNavBarHeight,
child: BottomNavigationBar(
backgroundColor: Colors.amber[800],
items: [
BottomNavigationBarItem(icon: Icon(Icons.call), label: 'Call'),
BottomNavigationBarItem(icon: Icon(Icons.message), label: 'Message'),
],
),
);
}
}

- 237,138
- 77
- 654
- 440
-
-
-
I tried that now and it requires a parameter `position` which I don't know what to insert. I want only the size to be reduces from normal->0 and vice versa not change its location – Kristi Jorgji Jun 23 '23 at 17:10
-
@KristiJorgji You need to use `Offset` there, start from `Offset.zero` and end at `Offset(0, y)`. It's better to ask a separate question for your need. – CopsOnRoad Jun 24 '23 at 06:02
Use Hidable library
My team developed 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.3
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(...),
)
For more information refer to the GitHub page -> https://github.com/insolite-dev/hidable

- 237,138
- 77
- 654
- 440

- 1,202
- 5
- 25
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)
)
],
),
),
);
}
}

- 11,459
- 1
- 23
- 35
-
1You should not use offstage for this solution since it isn't cheap in terms of processing. Also it offers no kind of animation. – mazen el zoor Apr 13 '20 at 22:55
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!

- 1,166
- 1
- 8
- 24
Check out this answer, => Bottom Navigation Scrolling it uses animation to hide the bottom navigation bar. You can also customize the animation.

- 910
- 1
- 14
- 32