How to handle ListView scroll direction

I have a dummy list of items I want to show a floating action button in swip up direction and hide it in down direction. how can I implement this functionality ?

class _MyHomePageState extends State<MyHomePage> {
  bool upDirection = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Container(
          child: Row(
            children: <Widget>[
              Expanded(
                  child: ListView.builder(
                    itemCount: 100,
                    itemBuilder: (context,index){
                      return ListTile(
                        title: Text(index.toString()),
                      );
                    },
                  ),
              )
            ],
          ),
        ),
      ),
      floatingActionButton:upDirection==true?FloatingActionButton(onPressed: (){},):Container() ,
    );
  }
}

Solution 1:

Screenshot:

enter image description here

All you need is a NotificationListener.onNotification callback:

NotificationListener<UserScrollNotification>(
  onNotification: (notification) {
    final ScrollDirection direction = notification.direction;
    return true;
  },
  child: ListView.builder(
    itemCount: 100,
    itemBuilder: (_, i) => ListTile(title: Text('$i')),
  ),
)

Full code:

bool _visible = true;
  
@override
Widget build(BuildContext context) {
  return Scaffold(
    floatingActionButton: AnimatedOpacity(
      duration: Duration(milliseconds: 400),
      opacity: _visible ? 1 : 0,
      child: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {},
      ),
    ),
    body: NotificationListener<UserScrollNotification>(
      onNotification: (notification) {
        final ScrollDirection direction = notification.direction;
        setState(() {
          if (direction == ScrollDirection.reverse) {
            _visible = false;
          } else if (direction == ScrollDirection.forward) {
            _visible = true;
          }
        });
        return true;
      },
      child: ListView.builder(
        itemCount: 100,
        itemBuilder: (_, i) => ListTile(title: Text('$i')),
      ),
    ),
  );
}

Solution 2:

Though the above solution answers the question, I think its a bit inefficient since you're calling setState() everytime a change in direction happens. This might work in small apps but in big complex apps can lead high time lags as when you call setState() the whole widget tree rebuild itself and its subsequent children.

My solution? Use a Provider and Consumer.

Provider acts like a reference to a widget and a certain variable of which you want to keep a track of and using consumer you can listen to change when you need and where you need.

Benefit over setState(), when the builder method of consumer is called it only rebuilds the widget which listens to it(in your case the bottom app bar) and doesn't affect the rest of the widget tree.

Also Providers are back-bone of flutter state management so I would highly recommend them knowing as soon as possible.