Hide bottom navigation bar on scroll down and vice versa

前端 未结 3 620
囚心锁ツ
囚心锁ツ 2020-12-19 13:36

I have a list 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 visib

3条回答
  •  一整个雨季
    2020-12-19 14:06

    While Naveen's solution works perfectly, I didn't like the idea of using setState to handle the visibility of the navbar. Every time the user would change scroll direction, the entire homepage including the appbar and body would rebuild which can be an expensive operation. I created a separate class to handle the visibility that uses a ValueNotifier to track the current hidden status.

    class HideNavbar {
      final ScrollController controller = ScrollController();
      ValueNotifier visible = ValueNotifier(true);
    
      HideNavbar() {
        visible.value = true;
        controller.addListener(
          () {
            if (controller.position.userScrollDirection ==
                ScrollDirection.reverse) {
              if (visible.value) {
                visible.value = false;
              }
            }
    
            if (controller.position.userScrollDirection ==
                ScrollDirection.forward) {
              if (!visible.value) {
                visible.value = true;
              }
            }
          },
        );
      }
    }
    

    Now all you do is create a final instance of HideNavbar in your HomePage widget.

    final HideNavbar hiding = HideNavbar();
    

    Now pass the instance's ScrollController to the ListView or CustomScrollView body of your Scaffold.

    body: CustomScrollView(
              controller: hiding.controller,
              ...
    

    Then surround your bottomNavigationBar with a ValueListenableBuilder that takes the ValueNotifier from the HideNavbar instance and the set the height property of the bottomNavigationBar to be either 0 or any other value depending on the status of the ValueNotifier.

    bottomNavigationBar: ValueListenableBuilder(
            valueListenable: hiding.visible,
            builder: (context, bool value, child) => AnimatedContainer(
              duration: Duration(milliseconds: 500),
              height: value ? 56.0 : 0.0,
              child: Wrap(
                children: [
                  BottomNavigationBar(
                    type: BottomNavigationBarType.fixed,
                    backgroundColor: Colors.blue,
                    fixedColor: Colors.white,
                    unselectedItemColor: Colors.white,
                    items: [
                      BottomNavigationBarItem(
                        icon: Icon(Icons.home),
                        title: Text('Home'),
                      ),
                      BottomNavigationBarItem(
                        icon: Icon(Icons.card_giftcard),
                        title: Text('Offers'),
                      ),
                      BottomNavigationBarItem(
                        icon: Icon(Icons.account_box),
                        title: Text('Account'),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
    

    This approaches keeps the HomePage as a StatelessWidget, avoids countless rebuilds, and doesn't require any external libraries. You can also implement this as a stream-based approach but that would require another library such as dart:async and would not be changing anything.

提交回复
热议问题