160

By default, flutter adds a glowing effect on ListView/GridView/... to overscrolls on android phones

I would like to remove this effect entirely or on one specific scrollable. I know that I can change ScrollPhysics to change between Bounce/Clamp. But this doesn't actually remove the glow effect.

What can I do ?

enter image description here

Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432

13 Answers13

298

The glow effect comes from GlowingOverscrollIndicator added by ScrollBehavior

To remove this effect, you need to specify a custom ScrollBehavior. For that, simply wrap any given part of your application into a ScrollConfiguration with the desired ScrollBehavior.

The following ScrollBehavior will remove the glow effect entirely :

class MyBehavior extends ScrollBehavior {
  @override
  Widget buildOverscrollIndicator(
      BuildContext context, Widget child, ScrollableDetails details) {
    return child;
  }
}

To remove the glow on the whole application, you can add it right under MaterialApp :

MaterialApp(
  builder: (context, child) {
    return ScrollConfiguration(
      behavior: MyBehavior(),
      child: child,
    );
  },
  home: new MyHomePage(),
);

To remove it on a specific ListView, instead wrap only the desired ListView :

ScrollConfiguration(
  behavior: MyBehavior(),
  child: ListView(
    ...
  ),
)

This is also valid if you want to change the effect. Like adding a fade when reaching borders of the scroll view.

Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • 11
    How can you remove the overscroll on iOS ? – TheRedhat Feb 28 '19 at 19:04
  • 2
    @TheRedhat I just have answered your question here, you can see how to remove the overscroll https://stackoverflow.com/questions/58645048/how-to-remove-overscroll-on-ios – Sergey Frolov Oct 31 '19 at 14:05
  • 3
    One more possible solution to avoid extending `ScrollBehavior` is to `disallowGlow()` on `OverscrollIndicatorNotification`. See here: https://stackoverflow.com/a/53154780/7621577 – rmalviya Dec 19 '19 at 11:43
  • can you please add full example or Git Code? – MohammedAli Jan 23 '20 at 10:11
  • because i have addCustomer Form Page and i used SingleChildScrollview so where to i add this code ? – MohammedAli Jan 23 '20 at 11:04
  • Flutter Documentation description: https://api.flutter.dev/flutter/widgets/ScrollBehavior/buildViewportChrome.html – Yauheni Pakala May 20 '20 at 10:51
  • @rmalviya I honestly don't see why would you want to "avoid" this method. However, your solution also does work but only for a `ListView`, not for a `SingleChildScrollView` – jujka Oct 30 '20 at 08:01
  • Remi Rousselet - I am using `ScrollablePositionedList.builder` how can I remove bouncing glow / scrolling glow? Kindly share your suggestion. Thanks. – Kamlesh Jun 23 '21 at 13:37
  • Remi Rousselet - I am facing this bouncing glow / scrolling glow issue because `ScrollablePositionedList.builder` does not support `controller` attribute. Your help will be highly appreciated. Thanks. – Kamlesh Jun 23 '21 at 13:38
  • Thanks @Remi Remi, It worked for me. You posted first here then I found the same solution at https://flutteragency.com/remove-scrollglow-in-flutter – Kamlesh Jul 02 '21 at 08:24
  • Low performance solution... not recommended – genericUser Aug 08 '21 at 14:34
  • 1
    as buildViewportChrome is deprecated on March `21, we may have new way to implement this. check on my answer below https://stackoverflow.com/a/68477729/2362966 – ejabu Jan 20 '22 at 04:16
98

The glow will disappear by changing the ListView's physics property to BouncingScrollPhysics to imitate the List behavior on iOS.

ListView.builder(
    physics: BouncingScrollPhysics(),
}
Eddy Liu
  • 1,463
  • 9
  • 6
37

The above solution did not work for me. I did this from another solution.

Wrap it with this widget to remove the shadow completely:

NotificationListener<OverscrollIndicatorNotification>(
  onNotification: (OverscrollIndicatorNotification overscroll) {
    overscroll.disallowIndicator();

    return true;
  },
  child: new ListView.builder(
    //Your stuff here. 
  ),
),
Hamed
  • 5,867
  • 4
  • 32
  • 56
Bensal
  • 3,316
  • 1
  • 23
  • 35
  • 1
    It's work but you must wrap to scroll widget parent if this widget inside another scroll widget. – Doan Bui Aug 31 '20 at 04:34
  • 1
    any solution for `ScrollablePositionedList.builder`, will be highly appreciated. Thanks. – Kamlesh Jun 23 '21 at 13:39
  • @Kamlesh Sorry, noob with ScrollablePositionedList.builder. I suggest you to ask a new question to get some attention from the community. – Bensal Jun 23 '21 at 14:37
  • 1
    Ok dear Bensal, Thanks, I will some more research on this topic and if I do not get any proper solution, I will post a new question. Thanks again :) – Kamlesh Jun 23 '21 at 19:06
  • 1
    for me adding a return statement worked for pageview NotificationListener( onNotification: (overscroll) { overscroll.disallowGlow(); return true; }, child: new ListView.builder( //Your stuff here. ), ), – Atharv Sharma Aug 30 '21 at 06:01
  • Also you can change physics property of ListView widget as well to `physics: const BouncingScrollPhysics(),` if you like that behaviour. – Wimukthi Rajapaksha Oct 06 '21 at 23:36
27

You don't need to build your own custom ScrollBehavior class. Instead, just wrap your scrollable widget in a ScrollConfiguration widget and set the behavior property to:

const ScrollBehavior().copyWith(overscroll: false).

Full code example:

ScrollConfiguration(
  behavior: const ScrollBehavior().copyWith(overscroll: false),
  child: PageView(
    physics: const PageScrollPhysics(),
    controller: model.pageController,
    children: [
      PageOne(),
      PageTwo(),
      PageThree(),
      PageFour(),
    ],
  ),
),
Code on the Rocks
  • 11,488
  • 3
  • 53
  • 61
25

You can try BouncingScrollPhysics with all list or grid or scrollview:

//ScrollView:
SingleChildScrollView(
      physics: BouncingScrollPhysics(),
)

//For ListView: 
ListView.builder(
    physics: BouncingScrollPhysics(),
}
//GridView
GridView.Builder(
    physics: BouncingScrollPhysics(),
)
Mohd Danish Khan
  • 1,044
  • 11
  • 12
20

You can wrap your SingleChildScrollView or ListView.

NotificationListener<OverscrollIndicatorNotification>(
  onNotification: (OverscrollIndicatorNotification overscroll) {
    overscroll.disallowGlow();
    return;
  },
  child: SingleChildScrollView()
)
20

Update on 2021

as buildViewportChrome is deprecated on March `21, we may have new way to implement this

A. Working Solution

class MyCustomScrollBehavior extends MaterialScrollBehavior {

  @override
  Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
    return child;
  }
}

class MainApp extends StatelessWidget {
  const MainApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      scrollBehavior: MyCustomScrollBehavior(),
      title: 'App Title',
      home: HomeUI(),
    );
  }
}

B. Explanation

By default, Flutter wraps any child widget into GlowingOverscrollIndicator as below code.

  @override
  Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
    switch (getPlatform(context)) {
      case TargetPlatform.iOS:
      case TargetPlatform.linux:
      case TargetPlatform.macOS:
      case TargetPlatform.windows:
        return child;
      case TargetPlatform.android:
      case TargetPlatform.fuchsia:
        return GlowingOverscrollIndicator(
          axisDirection: details.direction,
          color: Theme.of(context).colorScheme.secondary,
          child: child, // < ----------  our Child Widget is wrapped by Glowing Indicator
        );
    }
  }

So we can easily override it, by directly return child without wrapping it to GlowingOverscrollIndicator

class MyCustomScrollBehavior extends MaterialScrollBehavior {

  @override
  Widget buildOverscrollIndicator(
      BuildContext context, Widget child, ScrollableDetails details) {
    return child;
  }
}
ejabu
  • 2,998
  • 23
  • 31
17

You can also try

SingleChildScrollView(
      physics: ClampingScrollPhysics(),
)
Mehmet
  • 1,467
  • 1
  • 14
  • 19
16

try this work for me mybe work for you to

ScrollConfiguration(
          behavior: new ScrollBehavior()..buildViewportChrome(context, null, AxisDirection.down),
          child: SingleChildScrollView()
);
malik kurosaki
  • 1,747
  • 15
  • 9
  • 2
    What does this do? The `behavior` param expects a `ScrollBehavior` type, so you pass in the default `ScrollBehavior()` but call its `buildViewportChrome` method once, and ignore its return value and force "return self" with `..` syntax, how would this be different than simply pass in `behavior: ScrollBehavior()`? – WSBT Sep 01 '20 at 16:54
12

If you migrated to null safety, you might get issues with the behavior. You can use this method that works with null safety:

NotificationListener<OverscrollIndicatorNotification>(
    onNotification: (OverscrollIndicatorNotification? overscroll) {
      overscroll!.disallowGlow();
      return true;
    },
  child: child,
),
Ziyad
  • 354
  • 4
  • 13
  • Where exactly it's a good null safety practice? `overscroll?.disallowGlow();` – jujka Jun 23 '21 at 11:56
  • any solution for ScrollablePositionedList.builder, will be highly appreciated. Thanks. – Kamlesh Jun 23 '21 at 13:40
  • 1
    @egorikem If you migrate your project to null safety, you might want to have your code non-nullable otherwise you will get an error. – Ziyad Jun 23 '21 at 15:02
9

The currently accepted answer is outdated in the current version of Flutter.

Scroll behavior's ScrollBehavior.copyWith() method has an overscroll flag which can be set to false to avoid having to create your own ScrollBehavior class.

For example:

ScrollConfiguration(
    behavior: MaterialScrollBehavior().copyWith(overscroll: false),
    child : someScrollableWidget
)

`

It isn't good practice to just change the scroll behavior, as you may lose the native scrolling feel when running your app on different devices.

Sylith
  • 411
  • 4
  • 10
4

I have used below one for Scroll body without Scroll glow effect

@override
  Widget build(BuildContext context) {

     return Scaffold(
          body: Center(
            child: ScrollConfiguration(
              behavior: new ScrollBehavior()
                ..buildViewportChrome(context, null, AxisDirection.down),
              child: SingleChildScrollView(
ViramP
  • 1,659
  • 11
  • 11
2

After Flutter 2.10 update Previous NotificationListener parameter code has been removed/deprecated. New Code

NotificationListener<OverscrollIndicatorNotification>(
                      onNotification: (overscroll) {
                        overscroll.disallowIndicator(); //previous code overscroll.disallowGlow();
                        return true;
                      },
                      child: ListView(
                        padding: const EdgeInsets.symmetric(
                            horizontal: 15, vertical: 15),
                        scrollDirection: Axis.horizontal,
                        children: List.generate(
                            items.length,
                            (index) => Padding(
                                padding: const EdgeInsets.only(right: 15),
                                child: AspectRatio(
                                  aspectRatio: 13 / 9,
                                  child:
                                      LayoutBuilder(builder: (context, boxcon) {
                                    return Container(
                                      decoration: BoxDecoration(
                                        borderRadius: BorderRadius.circular(10),
                                        boxShadow: const [
                                          BoxShadow(
                                              color: Colors.black12,
                                              spreadRadius: 5,
                                              blurRadius: 12)
                                        ],
                                        image: DecorationImage(
                                            fit: BoxFit.cover,
                                            image: NetworkImage(items[index])),
                                        color: greengradientcolor,
                                      ),
                                    );
                                  }),
                                ))),
                      ),
                    ),