Flutter - Hiding FloatingActionButton

前端 未结 7 1667
悲哀的现实
悲哀的现实 2020-12-13 18:18

Is there any built in way in Flutter to hide a FloatingActionButton on ListView scrolling down and then showing it on scrolling up?

相关标签:
7条回答
  • 2020-12-13 18:29

    you can use below code to keep default animation

    floatingActionButton: _isVisible
            ? FloatingActionButton(...)
            : null,
    
    0 讨论(0)
  • 2020-12-13 18:30

    Quite an old question, but with the latest flutter there is a nicer (and shorter) solution in my opinion.

    The other solutions do work, but if you want a nice animation (comparable to the default Animation in Android), here you go:

    A NotificationListener informs you, whenever a user scrolls (up/down). With an AnimationController you can control the animation of the FAB.

    Here's a full example:

    class WidgetState extends State<Widget> with TickerProviderStateMixin<Widget> {
      AnimationController _hideFabAnimation;
    
      @override
      initState() {
        super.initState();
        _hideFabAnimation = AnimationController(vsync: this, duration: kThemeAnimationDuration);
      }
    
      @override
      void dispose() {
        _hideFabAnimation.dispose();
        super.dispose();
      }
    
      bool _handleScrollNotification(ScrollNotification notification) {
        if (notification.depth == 0) {
          if (notification is UserScrollNotification) {
            final UserScrollNotification userScroll = notification;
            switch (userScroll.direction) {
              case ScrollDirection.forward:
                if (userScroll.metrics.maxScrollExtent !=
                    userScroll.metrics.minScrollExtent) {
                  _hideFabAnimation.forward();
                }
                break;
              case ScrollDirection.reverse:
               if (userScroll.metrics.maxScrollExtent !=
                    userScroll.metrics.minScrollExtent) {
                  _hideFabAnimation.reverse();
                }
                break;
              case ScrollDirection.idle:
                break;
            }
          }
        }
        return false;
      }
    
      @override
      Widget build(BuildContext context) {
        return NotificationListener<ScrollNotification>(
          onNotification: _handleScrollNotification,
          child: Scaffold(
            appBar: AppBar(
              title: Text('Fabulous FAB Animation')
            ),
            body: Container(),
            floatingActionButton: ScaleTransition(
              scale: _hideFabAnimation,
              alignment: Alignment.bottomCenter,
              child: FloatingActionButton(
                elevation: 8,
                onPressed: () {},
                child: Icon(Icons.code),
              ),
            ),
          ),
        );
      }
    }
    
    0 讨论(0)
  • 2020-12-13 18:37

    You can use Visibility widget for handling the Visibility of child widget

    sample :

      floatingActionButton:
                Visibility(visible: _visibilityFlag , child: _buildFAB(context)),
    
    0 讨论(0)
  • 2020-12-13 18:41

    There are many ways of handing it. Let me list few here.

    1. You can use Visibility to hide/show FAB.

      floatingActionButton: Visibility(
        child: FloatingActionButton(...),
        visible: false, // set it to false
      )
      
    2. With Dart 2.2, you can use if condition like this:

      floatingActionButton: Column(
        children: <Widget>[
          if (shouldShow) FloatingActionButton(...), // visible if showShould is true
        ],
      )
      
    3. You can use Opacity widget.

      floatingActionButton: Opacity(
        opacity: shouldShow ? 1 : 0, // visible if showShould is true
        child: FloatingActionButton(...),
      )
      
    0 讨论(0)
  • 2020-12-13 18:42
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    
    void main() {
      runApp(new MyApp());
    }
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @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> {
      int _counter = 0;
      ScrollController _hideButtonController;
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
      var _isVisible;
      @override
      initState(){
        super.initState();
        _isVisible = true;
        _hideButtonController = new ScrollController();
        _hideButtonController.addListener((){
          if(_hideButtonController.position.userScrollDirection == ScrollDirection.reverse){
            if(_isVisible == true) {
                /* only set when the previous state is false
                 * Less widget rebuilds 
                 */
                print("**** ${_isVisible} up"); //Move IO away from setState
                setState((){
                  _isVisible = false;
                });
            }
          } else {
            if(_hideButtonController.position.userScrollDirection == ScrollDirection.forward){
              if(_isVisible == false) {
                  /* only set when the previous state is false
                   * Less widget rebuilds 
                   */
                   print("**** ${_isVisible} down"); //Move IO away from setState
                   setState((){
                     _isVisible = true;
                   });
               }
            }
        }});
      }
      @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('I realize I am crazy'),   
                      ],
                    ),
                  ),
                ),
              ],
            )
          ),
          floatingActionButton: new Visibility( 
            visible: _isVisible,
            child: new FloatingActionButton(
              onPressed: _incrementCounter,
              tooltip: 'Increment',
              child: new Icon(Icons.add),
            ),     
          ),
        );
      }
    }
    

    I apologize if I did not use listview since I do not know how to scroll with listview. I will answer the other parts of your question.

    First you need to create a scrollcontroller that will listen scrollPostion events

    If scrollcontroller manages to find either scrolldirection forward or reverse. You add a state that set a state to visible.

    When you draw the button, you wrap the button in a visibility class. You set the visible flag and the widget should ignore input commands.

    Edit: I cant seem to add links to ScrollController, ScrollerPosition, ScrollDirection, and Opacity. I guess you can search it yourself or somebody else edit in the links

    Edit2: Use CopsonRoad or use visibility widget, unless you want an unpainted widget in the layout tree

    Edit3: In light of newcomers using code as is, I would update the code to encourage better practices. Use visibility instead of Opacity. Remove io from setState. tested on Flutter 1.5.4-hotfix.2

    0 讨论(0)
  • 2020-12-13 18:43

    Other very good way is AnimatedOpacity

    AnimatedOpacity(
              opacity: isEnabled ? 0.0 : 1.0,
              duration: Duration(milliseconds: 1000),
              child: FloatingActionButton(
                 onPressed: your_method,
                 tooltip: 'Increment',
                 child: new Icon(Icons.add),
              ),
            )
    
    0 讨论(0)
提交回复
热议问题