InkWell 未显示涟漪效应

InkWell not showing ripple effect

点击容器会触发 onTap() 处理程序,但不会显示任何墨水飞溅效果。

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,
          ),
        ),
      ),
    );
  }
}

我也试过将 InkWell 放在 Container 中,但没有成功。

我认为给容器上色是遮盖墨水的效果

https://api.flutter.dev/flutter/material/InkWell/InkWell.html

此代码似乎有效

  body: new Center(
    child: new Container(
      child: new Material(
        child: new InkWell(
          onTap: (){print("tapped");},
          child: new Container(
            width: 100.0,
            height: 100.0,
          ),
        ),
        color: Colors.transparent,
      ),
      color: Colors.orange,
    ),
  ),

只需点击中间的方块。

编辑:我找到了错误报告。 https://github.com/flutter/flutter/issues/3782

This is actually as expected, though we should update the docs to make it clearer.

What's going on is that the Material spec says that the splashes are actually ink on the Material. So when we splash, what we do is we literally have the Material widget do the splash. If you have something on top of the Material, we splash under it, and you can't see it.

I have wanted to add a "MaterialImage" widget that conceptually prints its image into the Material as well so that then the splashes would be over the image. We could have a MaterialDecoration which does something similar for a Decoration. Or we could have Material itself take a decoration. Right now it takes a color, but we could extend that to taking a whole decoration. It's not clear whether it's really material-spec-compatible to have a material with a gradient, though, so I'm not sure whether we should do that.

In the short run, if you just need a workaround, you can put a Material on top of the container, with the material set to use the "transparency" type, and then put the ink well inside that.

--嘻嘻

更新:Hixie 去年合并了一个新的 Ink 解决方案。 Ink 提供了一种在图像上泼墨的便捷方式。

  testWidgets('Does the Ink widget render anything', (WidgetTester tester) async {
    await tester.pumpWidget(
      new Material(
        child: new Center(
          child: new Ink(
            color: Colors.blue,
            width: 200.0,
            height: 200.0,
            child: new InkWell(
              splashColor: Colors.green,
              onTap: () { },
            ),
          ),
        ),
      ),
    );


Material(
  color: Colors.grey[800],
  child: Center(
    child: Ink.image(
      image: AssetImage('cat.jpeg'),
      fit: BoxFit.cover,
      width: 300.0,
      height: 200.0,
      child: InkWell(
        onTap: () { /* ... */ },
        child: Align(
          alignment: Alignment.topLeft,
          child: Padding(
            padding: const EdgeInsets.all(10.0),
            child: Text('KITTEN', style: TextStyle(fontWeight: FontWeight.w900, color: Colors.white)),
          ),
        )
      ),
    ),
  ),
)

请注意:我没有测试新的 Ink Widget。我处理了 ink_paint_test.dart 和 Ink class 文档

中的代码

https://github.com/Hixie/flutter/blob/1f6531984984f52328e66c0cd500a8d517964564/packages/flutter/test/material/ink_paint_test.dart

https://github.com/flutter/flutter/pull/13900

https://api.flutter.dev/flutter/material/Ink-class.html

在您添加

之前,InkWell() 永远不会显示涟漪效果
onTap : () {} 

或任何回调,如 onDoubleTap、onLongPress 等

InkWell 中的参数,因为它仅在您指定此参数时才开始聆听您的敲击声。

我 运行 遇到了同样的问题,试图在 ListView 中创建 InkWell 的交替颜色。在这种特殊情况下,有一个简单的解决方案:将替代项包装在一个主要使用 t运行sparenttint/brightness 更改的容器中——InkWell 触摸动画在其下方仍然可见。不需要 Material。请注意,在尝试使用 Materal 解决此问题时还有其他问题——例如,它将覆盖您使用默认设置的 DefaultTextStyle(它安装了 AnimatedDefaultTextStyle),这是一个巨大的痛苦。

截图:


使用 Ink 小部件包裹在 InkWell.

InkWell(
  onTap: () {}, // Handle your onTap 
  child: Ink(
    width: 200,
    height: 200,
    color: Colors.blue,
  ),
)

更好的方法是使用 Ink 小部件而不是任何其他小部件。

您可以在 Ink 小部件本身中定义它,而不是在容器内定义 color

下面的代码可以工作。

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.

  1. InkWell 小部件必须有一个 Material 小部件作为祖先,否则它无法显示效果。例如:

    Material(
      child : InkWell(
        child : .....
    
  2. 需要添加onTap方法才能看到实际效果,如

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

让我们来看看要点,看看下面的一些例子,试着理解 InkWell 的实际概念。

  • 在下面的示例中,Material 是带有 onTap 的 InkWell 的父级,但它仍然无法正常工作。请尝试理解它的概念。您应该为容器或其他小部件提供一些边距以显示效果。实际上下面的代码工作正常但我们看不到,因为我们没有提供任何边距或对齐所以它没有 space 来显示效果。

    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,
            ),  
          ),
        ),
      );
    }
    
  • 下面的例子只显示向上的 InkWell 效果,因为我们提供了 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,
            ),
          ),
        ),
      );
    }
    
  • 低于经验值。在所有页面中显示效果,因为中心从所有侧面创建边距。从上、左、右和下居中对齐它的子窗口小部件。

    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
  • 包裹你的Widget
  • Material
  • 包裹 InkWell
  • 无论如何设置不透明度为 0%。例如: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");},
      ),
    )
    

我遇到了类似的问题,将 Inkwell 添加到现有的复杂 Widget 中,其中 Container 包装了带有颜色的 BoxDecoration。通过添加 Material 和 Inkwell 的方式表明 Inkwell 仍然被 BoxDecoration 遮挡,所以我只是让 BoxDecoration 的颜色稍微不透明,这样可以看到 Inkwell

圆形小部件的解决方法,如下:

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: () {}),
        ],
      ),
    ),
  )

我找到了适合我的解决方案。我认为它可以帮助你:

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

Color 已提供给 Material 小部件。它是您的小部件的默认颜色。 您可以使用 Inkwell splashColor 属性 调整波纹效果的颜色。

添加 onTap:(){} 侦听器后,连锁反应应该可以正常工作。如果您在 InkWell() 小部件中使用 BoxShadow() 则它不起作用。

这对我有用:

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');
      },
    ));

在这里尝试了很多答案后,它是以下组合:

  1. 设置splashColor
  2. Material(color: Colors.white.withOpacity(0.0), ..)
  3. 中包装 InkWell

感谢这里的回答让这两点成为可能

对我来说这是另一个问题。当我将 onTap 函数作为我的小部件的参数定义如下时,InkWell 没有显示涟漪效应。

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

我不知道有什么区别,但下一个代码运行良好。

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

如果您想在任何小部件上获得 Ripple Effect,只需:

1- 使用 MaterialInkwell.

包装小部件

2- 从 Material.

中为小部件设置颜色

3- 从不颜色 设置为您希望其波纹的小部件。

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

设置 InkWell 容器的颜色

放置在 Material 小部件内的任何子小部件都采用 Material 小部件中设置的颜色。所以,我们应该从 Material 的颜色 属性 本身设置颜色。您不能从任何父 Container 小部件设置它。

使用 Material 父控件创建 InkWell 时要注意的另一个重要事项是,您应该从 Material 的 属性 本身设置颜色。您不能从 Container.

中设置它

因此,我们修复 InkWell 效果和容器颜色的代码如下所示:

Container(
    margin: EdgeInsets.all(12),
    height: 50.0,
    width: 100.0,
    decoration: BoxDecoration(boxShadow: [
      BoxShadow(
          color: Colors.grey, blurRadius: 4, offset: Offset(0, 2))
    ]),
    child: Material(
      color: Colors.blue,
      child: InkWell(
        child: Center(
            child: Text("My Chip",
                style: Theme.of(context).textTheme.body1)),
        onTap: () {},
      ),
    ),
  )

我能够通过使用 Stack 来解决我的情况。

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

此页面上的其他答案对我不起作用的原因是我的自定义小部件隐藏了墨迹效果并且我没有纯图像(所以我无法使用 Ink.image ).

编辑:

如果您 .

,您仍然可以使用 Ink.image

向 Material 添加透明颜色在我的案例中有效:

  child: new Material(
    color: Colors.transparent
    child: new InkWell(
      onTap: (){},
      child: new Container(
        width: 100.0,
        height: 100.0,
        color: Colors.amber,
      ),
    ),
  ),

现在使用 MaterialButton,在较新的版本中 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),
          ),
        ),
      ),
    );
  }

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

InkWell之前添加Material,并将color设置为Colors.transparent

要处理涟漪效应,您应该使用以下规则:

  1. onTap 不应该是 null(或空的)。
  2. InkWell 必须在任何 Material 小部件中
  1. Create a widget that supports tap.
  2. Wrap it in an InkWell widget to manage tap callbacks and ripple animations.

documentation

中提到了 2 分

示例:

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

简单易懂的快速解决方案:

此解决方案适用于小部件树的任何位置。 只需在 InkWell 之前添加额外的 Material,如下所示:

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

参考: https://api.flutter.dev/flutter/material/InkWell-class.html 名为“墨水飞溅不可见!”的部分