How to disable default Widget splash effect in Flutter?
Asked Answered
S

13

74

How can I disable the default splash/ripple/ink effect on a Widget? Sometimes the effect is unwanted, such as in the following TextField case:

Septuplet answered 25/4, 2018 at 10:57 Comment(0)
A
152

Per @hunter's suggestion above, I found that by setting both highlightColor and splashColor in my theme to Colors.transparent removed the ripple.

I do hold some concerns that setting highlightColor might have some knock-on effects, but I haven't noticed any yet.

Edit: While my original answer has loads of up-votes, the more I learn, the more I've realised that it really isn't the right way to do it. As several people have pointed out below, a better solution is to use the splashFactory. For example, the code below shows it being set directly via the style, or you can set it in your theme too:

ElevatedButton(
  onPressed: onPressed,
  style: ElevatedButton.styleFrom(
    splashFactory: NoSplash.splashFactory,
  ),
  child: child,
);
Alded answered 8/1, 2019 at 1:30 Comment(3)
This also removes the ripple effect from widgets such as InkWell and InkResponseChamorro
Setting highlightColor to transparent makes using Theme.of(context).highlightColor pointlessRone
Doesn't work for TextButton. TextButton.styleFrom(splashFactory: NoSplash.splashFactory); I can't see why.Galiot
G
80

You can wrap the component into Theme and set the properties splashColor and highlightColor to transparent on ThemeData

Theme(
  data: ThemeData(
    splashColor: Colors.transparent,
    highlightColor: Colors.transparent,
  ),
  child: YourWidget(),
);
Grandpapa answered 2/11, 2019 at 17:14 Comment(1)
Best answer here, not changing whole-app theme! You can even use Theme.of(context).copyWith instead of ThemeData as it will keep already defined theme data instead of having flutter's default ones :)Dragrope
N
33

Use NoSplash.splashFactory

Set to a theme

final yourTheme = ThemeData.light();
...
Theme(
  data: yourTheme.copyWith(
    splashFactory: NoSplash.splashFactory,
  ),
  ...
)

Set to a material widget

ElevatedButton(
  style: ElevatedButton.styleFrom(
    splashFactory: NoSplash.splashFactory,
  ),
  onPressed: () { },
  child: Text('No Splash'),
)
Nuisance answered 8/7, 2021 at 12:26 Comment(0)
S
22

You can replace the Theme's splashFactory with one that doesn't paint anything:

class NoSplashFactory extends InteractiveInkFeatureFactory {
  const NoSplashFactory();

  @override
  InteractiveInkFeature create({
    MaterialInkController controller,
    RenderBox referenceBox,
    Offset position,
    Color color,
    TextDirection textDirection,
    bool containedInkWell = false,
    Rect Function() rectCallback,
    BorderRadius borderRadius,
    ShapeBorder customBorder,
    double radius,
    VoidCallback onRemoved,
  }) {
    return NoSplash(
      controller: controller,
      referenceBox: referenceBox,
    );
  }
}

class NoSplash extends InteractiveInkFeature {
  NoSplash({
    @required MaterialInkController controller,
    @required RenderBox referenceBox,
  })  : assert(controller != null),
        assert(referenceBox != null),
        super(
          controller: controller,
          referenceBox: referenceBox,
        );

  @override
  void paintFeature(Canvas canvas, Matrix4 transform) {}
}

And wrap your widget with it:

child: new Theme(
  data: new ThemeData(splashFactory: const NoSplashFactory()),
  child: new TextField(...),
),

Originally answered by HansMuller on a GitHub PR.

Septuplet answered 25/4, 2018 at 10:57 Comment(3)
you could also just define a transparent splashColor; ie: ThemeData(splashColor: Colors.transparent)Alienism
The @override annotation should be removed as InteractiveInkFeatureFactory is an abstract class in latest version of flutter.Mitis
Now it's merged in flutter! Use splashFactory: NoSplash.splashFactoryHellion
P
15

I'll modify Camilo's approach just to be sure we don't override other properties of the parent theme.

var color = Colors.transparent;
Theme(
  data: Theme.of(context).copyWith(
    highlightColor: color,
    splashColor: color,
    hoverColor: color,
  ),
  child: YourWidget(),
)
Petrel answered 31/12, 2020 at 11:4 Comment(0)
T
7

I have tried the above answer without success(splashColor: Colors.transparent, highlightColor: Colors.transparent,).

My solution was to only set hoverColor:Colors.transparent

Tern answered 5/6, 2020 at 20:22 Comment(1)
actually in order to remove every highlight, hover, splashing effect on an InkWell, I had to set both splashColor, highlightColor and hoverColor as well, but it worked by setting on the inkwell itself, I did not need to use the Theme wrapperMargalit
M
7

Set highlightColor,splashColor to transparent and splashFactory to NoSplash as shown below in your material apptheme.

MaterialApp(
   theme: ThemeData(
      highlightColor: Colors.transparent,
      splashColor: Colors.transparent,
      splashFactory: NoSplash.splashFactory,,
    )
 )
Mansoor answered 27/4, 2023 at 16:44 Comment(0)
P
3

If a widget has splashColor and highColor like IconButton set it to transparant.

IconButton(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
color: HexColor.fromHex(AppColors.navigationIconColor),
icon: SvgPicture.asset(
  Platform.isAndroid
      ? "assets/back_button_android.svg"
      : "assets/back_button.svg",
  fit: BoxFit.cover,
),
onPressed: onPress,

);

Phillipphillipe answered 12/10, 2023 at 10:5 Comment(0)
T
2

As I was looking for a way to remove the slash from list overscroll, none of the ThemeData related solutions worked for me. I thought that this question was the same as the one I had, so for any users facing the same misunderstanding, the following solution proved to work, and is pretty neat when put into a stateless widget as you can see below:

class NoSplash extends StatelessWidget {
  NoSplash({this.child});

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return NotificationListener<OverscrollIndicatorNotification>(
        onNotification: (OverscrollIndicatorNotification overscroll) {
          overscroll.disallowGlow();
          return true;
        },
        child: child);
  }
}

The way to use this is to simply wrap your widget with NoSplash(child: )

Hope someone finds this useful!

Trinary answered 29/9, 2020 at 4:55 Comment(2)
That looks neat. This question is generally about tap effects though, so I feel like it might be a good idea if you ask a new question like "How to disable scroll glow effect in Flutter" and answer it yourself. Will likely make it easier to find for people searching for that.Septuplet
Yes it took me some time to realize, and then I found part of this elsewhere on SO, so this is why I'm posting it here. In case someone has misunderstood their own needs like me I mean :)Trinary
T
2

I found this question while looking for a solution to disable splash on ElevatedButton. all solutions presented here did not work for my problem, even though Theme(data: ThemeData(... NoSplash..)) was working but for some reason did not work. I set overlayColor:.. in ButtonStyle() to transparent like this: overlayColor: MaterialStateProperty.all(Colors.transparent), and worked. hope this will help someone

Tactless answered 23/9, 2022 at 15:57 Comment(0)
J
1

for ElevatedButton. (Flutter 2.20+)

class NoSplashState extends MaterialStatesController{
  @override
  void update(MaterialState state, bool add) {
  }
}


ElevatedButton(
   statesController: NoSplashState(),
   ...
)
Jailbird answered 13/6, 2023 at 5:56 Comment(0)
M
1
@override
Widget build(BuildContext context){
  // You can use your custom theme like AppTheme.of(context).materialThemeData
  final yourTheme = Theme.of(context) ;
  
  return Theme(
    data: yourTheme.copyWith(
      // removes splash effect
      splashFactory: NoSplash.splashFactory,
      // removes color when holding the button
      highlightColor: Colors.transparent,
    ),
    child: yourChild
  );
}
Modernity answered 17/9, 2023 at 7:43 Comment(0)
E
0

For radio button you can do like this:

Theme(
                      data: Theme.of(context).copyWith(
                        radioTheme: const RadioThemeData(splashRadius: 0),
                      ),
                      child: Radio<T>(
                        value: e,
                        groupValue: widget.value,
                        onChanged: (value) {
                          widget.onChanged(value);
                          state.didChange(value);
                        },
                      ),
                    ),
Edh answered 2/7 at 8:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.