Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - Hiding FloatingActionButton

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

like image 622
Marcin Szałek Avatar asked Aug 11 '17 09:08

Marcin Szałek


People also ask

How do you hide FloatingActionButton?

To show and hide a FloatingActionButton with the default animation, just call the methods show() and hide() . It's good practice to keep a FloatingActionButton in the Activity layout instead of putting it in a Fragment, this allows the default animations to work when showing and hiding.

What is a floating action button?

A floating action button (FAB) is a circular button that triggers the primary action in your app's UI. This page shows you how to add the FAB to your layout, customize some of its appearance, and respond to button taps.

How do you align the floating action button on flutter?

Center Align FloatingActionButton in Flutter If you are using Scaffold, you may set floatingActionButtonLocation property to FloatingActionButtonLocation. centerFloat to center make the FloatingActionButton float in the center of the screen at bottom.


2 Answers

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

like image 84
user1462442 Avatar answered Sep 25 '22 11:09

user1462442


Without animation:

  • Using Visibility widget:

    floatingActionButton: Visibility(   visible: false, // Set it to false   child: FloatingActionButton(...), ) 
  • Using Opacity widget:

    floatingActionButton: Opacity(   opacity: 0, // Set it to 0   child: FloatingActionButton(...), ) 
  • Using ternary operator:

    floatingActionButton: shouldShow ? FloatingActionButton() : null, 
  • Using if condition:

    floatingActionButton: Column(   children: <Widget>[     if (shouldShow) FloatingActionButton(...), // Visible if condition is true   ], ) 

With animation:

enter image description here

This is just one example of using animation, you can create different types of UI using this approach.

bool _showFab = true;    @override Widget build(BuildContext context) {   const duration = Duration(milliseconds: 300);   return Scaffold(     floatingActionButton: AnimatedSlide(       duration: duration,       offset: _showFab ? Offset.zero : Offset(0, 2),       child: AnimatedOpacity(         duration: duration,         opacity: _showFab ? 1 : 0,         child: FloatingActionButton(           child: Icon(Icons.add),           onPressed: () {},         ),       ),     ),     body: NotificationListener<UserScrollNotification>(       onNotification: (notification) {         final ScrollDirection direction = notification.direction;         setState(() {           if (direction == ScrollDirection.reverse) {             _showFab = false;           } else if (direction == ScrollDirection.forward) {             _showFab = true;           }         });         return true;       },       child: ListView.builder(         itemCount: 100,         itemBuilder: (_, i) => ListTile(title: Text('$i')),       ),     ),   ); } 
like image 43
CopsOnRoad Avatar answered Sep 25 '22 11:09

CopsOnRoad