How to show a widget only when user is scrolling?

969

You are right, there aren't any onScroll events on GestureDetector, but there are onVerticalDrag events, which are basically the same, with another name.

But, for that, you don't actually need a GestureDetector. You can listen to the scroll changes, handling the ScrollStartNotification and ScrollEndNotification notifications with a NotificationListener, since you are already using a SingleChildScrollView.

I've created a little example to show you that which will produce the following: On scroll a flag to display the button is set to true and at the end, it will reset back to false and rebuild the tree with no button after 5 seconds if no more scroll notifications come in between (that's the reason why you don't set the _buttonShowing = false after the Future completes but before.

example

bool _buttonShowing = false;

  @override
  Widget build(BuildContext context) {
    List<Widget> columnWidgets = List<Widget>.filled(100, Container(height: 100.0, child: Placeholder()));

    if (_buttonShowing) {
      columnWidgets = List.from(columnWidgets)
        ..insert(
            3, Visibility(child: RaisedButton(child: Text('Press me'), onPressed: () {}), visible: _buttonShowing));
    }

    return Scaffold(
      appBar: AppBar(),
      body: NotificationListener<ScrollNotification>(
        onNotification: (scrollNotification) {
          if (scrollNotification is ScrollStartNotification) {
            if (!_buttonShowing) {
              setState(() => _buttonShowing = true);
            }
          } else if (scrollNotification is ScrollEndNotification) {
            if (_buttonShowing) {
              _buttonShowing = false;
              Future.delayed(Duration(seconds: 5)).then((_) => setState(() {}));
            }
          }
        },
        child: SingleChildScrollView(
          child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: columnWidgets),
        ),
      ),
    );
  }
Share:
969
mirkancal
Author by

mirkancal

Software Engineer from Kyiv, Ukraine. Working professionally with Flutter for three years, started during my senior project, when Flutter was Alpha.

Updated on December 09, 2022

Comments

  • mirkancal
    mirkancal over 1 year

    I want to hide buttons on screen and show them after user starts scrolling till for the 5 seconds from the last scroll.

    I've wrapped my SingleChildScrollView with GestureDetector and change the visibility value from onTap callback to hide my buttons with Visibility widget. However, there is no event like onScroll on GestureDetector.

    Is there anyone who succesfully implement that effect or is there any built-in animation for what I'm trying to achieve?

  • mirkancal
    mirkancal about 5 years
    Thank you for your help, those properties seems to will work. However it locks my UI if I wrap GestureDetector with SingleChildScrollView, like in your example, and If I wrap my SingleChildScrollView with GestureDetector, nothing happens.
  • Miguel Ruivo
    Miguel Ruivo about 5 years
    Actually you don't need a GestureDetector for that. By using only a SingleChildScrollView and a NotificationListener to handle the notifications that you need (start and end) you should be fine. I've edited my answer accordingly and provided a little example.
  • mirkancal
    mirkancal about 5 years
    Its working but when there are not enough items to scroll, the buttons don't show up. I guess it doesn't render SingleChildScrollView if it isn't needed. And when there is enough items to scroll, the buttons show only for once. Any idea?
  • Miguel Ruivo
    Miguel Ruivo about 5 years
    SingleChildScrollView won't scroll if you actually don't need a scroll. You shouldn't expect a user to start scrolling if the screen is already displaying all of its content so you shouldn't rely on scroll to display the button for that scenario IMO.
  • mirkancal
    mirkancal about 5 years
    Thank you, I think I have to find another solution.