Mohith7548
Mohith7548

Reputation: 1360

Hide Bottom Navigation bar on Scroll in Flutter

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?

Upvotes: 19

Views: 50144

Answers (7)

theiskaa
theiskaa

Reputation: 2423

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(...),
)

overview gif

For more information refer to the GitHub page -> https://github.com/insolite-dev/hidable

Upvotes: 7

mr.Penguin
mr.Penguin

Reputation: 1599

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!

Upvotes: 3

CopsOnRoad
CopsOnRoad

Reputation: 267364

Screenshot (Null safe):

enter image description here


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'),
        ],
      ),
    );
  }
}

Upvotes: 4

Brendan
Brendan

Reputation: 1157

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

Upvotes: 0

Josteve Adekanbi
Josteve Adekanbi

Reputation: 12673

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)
            )
          ],
        ),
      ),
    );
  }
}

Upvotes: 2

Rakesh Lanjewar
Rakesh Lanjewar

Reputation: 663

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

Upvotes: 10

moonvader
moonvader

Reputation: 21081

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

Upvotes: 5

Related Questions