InkWell not showing ripple effect

Viewed 157602

Tapping the container triggers the onTap() handler but does not show any ink splash effect.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new InkWell(
          onTap: (){print("tapped");},
          child: new Container(
            width: 100.0,
            height: 100.0,
            color: Colors.orange,
          ),
        ),
      ),
    );
  }
}

I tried putting the InkWell inside the Container as well but in vain.

22 Answers

Screenshot:

enter image description here


Use Ink widget wrapped in an InkWell.

InkWell(
  onTap: () {}, // Handle your onTap 
  child: Ink(
    width: 200,
    height: 200,
    color: Colors.blue,
  ),
)
  1. The InkWell widget must have a Material widget as an ancestor otherwise it can't show effects. E.g.:

    Material(
      child : InkWell(
        child : .....
    
  2. you have to add onTap method to see the actual effects as like

     Buttons {RaisedButton,FlatButton etc}.
     e.g -> Material(
                 child : InkWell(
                         onTap : (){}
                         child : .....
    

Let's come to the main points see some examples below and try to understand the actual concepts of InkWell.

  • In Below example Material is parent of InkWell with onTap but it still not working. Please try to understand the concept of it. You should provide some margin to container or other widget to show the effects. Actually below code working fine but we can't see because we did not provide any margin or align so it has no space to show the effects.

    Widget build(BuildContext context) {
      return Center(
        child: Material(
          child: new InkWell(
            onTap: () {
              print("tapped");
            },
            child: new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.orange,
            ),  
          ),
        ),
      );
    }
    
  • Below example show InkWell effects only to upwards because we provide space {margin}.

    Widget build(BuildContext context) {
      return Center(
        child: Material(
          child: new InkWell(
            onTap: () {
              print("tapped");
            },
            child: new Container(
              margin: EdgeInsets.only(top: 100.0),
              width: 100.0,
              height: 100.0,
              color: Colors.orange,
            ),
          ),
        ),
      );
    }
    
  • Below exp. show the effects in all the page because center create margin from all the side. Centre align it's child widget from top, left, right and bottom.

    Widget build(BuildContext context) {
      return Center(
        child: Material(
          child: new InkWell(
            onTap: () {
              print("tapped");
            },
            child: Center(
              child: new Container(
                width: 100.0,
                height: 100.0,
                color: Colors.orange,
              ),
            ),
          ),
        ),
      );
     }
    

InkWell() will never show the ripple effect until you add the

onTap : () {} 

or any of the callbacks like onDoubleTap, onLongPress etc.

parameter inside the InkWell as it starts listening to your taps only when you specify this parameter.

I have found this solution for me. I think it can help you:

Material(
      color: Theme.of(context).primaryColor,
      child: InkWell(
        splashColor: Theme.of(context).primaryColorLight,
        child: Container(
          height: 100,
        ),
        onTap: () {},
      ),
    )

Color is given to Material widget. It is the default color of your widget. You can adjust color of ripple effect using splashColor property of Inkwell.

A better way is to use the Ink widget instead of any other widget.

Instead of defining color inside container you can define it in Ink widget itself.

Below code will work.

Ink(
  color: Colors.orange,
  child: InkWell(
    child: Container(
      width: 100,
      height: 100,
    ),
    onTap: () {},
  ),
)

Do not forget to add a onTap: () {} in the InkWell else it will not show the ripple effect too.

If you want a Ripple Effect on any widget just:

1- Wrap widget with Material and Inkwell.

2- set color to widget from Material.

3- Never set color to the widget you want it to ripple.

   Material (
   color: const Color(0xcffFF8906),
   child: InkWell(
   ontap:() { },
   child: Container(
   color: Colors.transparent,
   height: 80,
   width: 80,
 )

This is the best way I found and use it always. You can try it.

  • Wrap your Widget with InkWell
  • Wrap InkWell with Material
  • Set the opacity 0% anyhow. e.g.: color: Colors.white.withOpacity(0.0),

    Material(
      color: Colors.white.withOpacity(0.0),
      child: InkWell(
        child: Container(width: 100, height: 100),
        onTap: (){print("Wow! Ripple");},
      ),
    )
    

This is working for me:

Material(
    color: Colors.white.withOpacity(0.0),
    child: InkWell(
      splashColor: Colors.orange,
      child: Text('Hello'), // actually here it's a Container wrapping an image
      onTap: () {
        print('Click');
      },
    ));

After trying many answers here, it was a combination of:

  1. Setting splashColor
  2. Wrapping InkWell in Material(color: Colors.white.withOpacity(0.0), ..)

Thanks to the answers here that make those 2 points

child: Material(
color: Colors.transparent
child: InkWell(
  onTap: (){ print("this Ripple!";},
  splashColor: Colors.greenAccent,
  child: Container(
    height:100.0,
    color: Colors.white,
  ),
),
),

Add Material before InkWell and set color to Colors.transparent.

Quick solution in easy words:

This solution works in any place of the widget tree. Just add additional Material before InkWell, like so:

return Container(
  .......code.......
  ),
  child: Material(
    type: MaterialType.transparency,
    child: InkWell(
      onTap: () {},
      child: Container(
        .......code.......
      ),
    ),
  ),
);

Reference: https://api.flutter.dev/flutter/material/InkWell-class.html Section called "The ink splashes aren't visible!"

I ran into this same problem trying to create an alternating color of InkWell's in a ListView. In that particular case, there's a simple solution: wrap the alternates in a Container that uses a mostly transparent tint/brightness change -- the InkWell touch animation will still be visible beneath it. No Material needed. Note there are other issues when trying to work around this with a Materal -- e.g., it will override a DefaultTextStyle you're using with the default (it installs an AnimatedDefaultTextStyle) which is a huge pain.

After you added onTap:(){} listener, ripple effect should work fine. It doesn't work if you use BoxShadow() with in the InkWell() widget.

I was able to make my situation work by using a Stack.

Stack(
  children: [
    MyCustomWidget(), //              <--- Put this on bottom
    Material(
      color: Colors.transparent,
      child: InkWell(
        onTap: () {},
        child: Ink(
          width: 100,
          height: 100,
        ),
      ),
    ),
  ],
),

The reason that the other answers on this page weren't working for me is that my custom widget hid the ink effect and I didn't have a plain image (so I couldn't use Ink.image).

Edit:

You still may be able to use Ink.image if you convert the image to the right format.

now using MaterialButton, in newer version flutter


Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16.0),
      child: MaterialButton(
        child: Text(
          labelText,
          style: TextStyle(fontSize: 22),
        ),
        onPressed: () {},
        color: backgroundColor,
        height: 45,
        minWidth: double.infinity,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.all(
            Radius.circular(16),
          ),
        ),
      ),
    );
  }

For handling ripple effect you should use the below rules:

  1. onTap shouldn't be null (or empty).
  2. InkWell must be inside any of the Material Widgets

I was hit by a similar problem adding an Inkwell to an existing complex Widget with a Container wrapping a BoxDecoration with a color. By adding the Material and Inkwell in the way suggested the Inkwell was still obscured by the BoxDecoration so I just made the BoxDecoration's color slightly opaque which allowed the Inkwell to be seen

The solution to circular widgets, do like below:

Material(
    color: Colors.transparent,
    child: Container(
      alignment: Alignment.center,
      height: 100,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          IconButton(
              enableFeedback: true,
              iconSize: 40,
              icon: Icon(
                Icons.skip_previous,
                color: Colors.white,
                size: 40,
              ),
              onPressed: () {}),
          IconButton(
            iconSize: 100,
            enableFeedback: true,
            splashColor: Colors.grey,
            icon: Icon(Icons.play_circle_filled, color: Colors.white, size: 100),
            padding: EdgeInsets.all(0),
            onPressed: () {},
          ),
          IconButton(
              enableFeedback: true,
              iconSize: 40,
              icon: Icon(
                Icons.skip_next,
                color: Colors.white,
                size: 40,
              ),
              onPressed: () {}),
        ],
      ),
    ),
  )

For me it was another problem. InkWell was not showing ripple effect when i had onTap function as parameter of my widget defined as below.

Function(Result) onTapItem;
...
onTap: onTapItem(result),

I don't know what's the difference, but next code is working well.

onTap: (){ onTapItem(result); },

Adding transparent color to Material worked in my case:

  child: new Material(
    color: Colors.transparent
    child: new InkWell(
      onTap: (){},
      child: new Container(
        width: 100.0,
        height: 100.0,
        color: Colors.amber,
      ),
    ),
  ),
  1. Create a widget that supports tap.
  2. Wrap it in an InkWell widget to manage tap callbacks and ripple animations.

thats 2 point mention in documentation

example:

InkWell(
        child: TextButton(
          onPressed: () {},
          child: Text('Tapped'),
          ),
        ),
      ),

Single Line:

Use splashColor widget in an InkWell.

InkWell(
  onTap: () {}, // Handle your onTap 
  splashColor: Colors.grey,
  child: Container(
    width: 200,
    height: 200,
  ),
)
Related