Flutter:如何使卡片可点击?

139

我有一个简单的卡片,例如new Card(child: new Text('My cool card')),我想让用户能够点击卡片上的任何位置来触发一些功能,但是Card没有onPressed方法。我可以在底部添加一个按钮,但这对于这种情况不是理想的解决方案。

有人知道如何使整个卡片可点击吗?


你尝试过用GestureDetector包装一下吗? - Colin Ricardo
11个回答

243

Flutter使用组合而非属性来实现功能。将所需的小部件包装到可点击的小部件中,以实现所需效果。

一些可点击的小部件:GestureDetectorInkWellInkResponse

GestureDetector(
  onTap: () => ......,
  child: Card(...),
);

当手势检测器列表存在时,它的效果如何?我最感兴趣的是在ListView中的使用。 - silentsudo
那是相同的东西。 - Rémi Rousselet
3
这个可以运行,但是没有显示任何涟漪效果。我尝试用 InkWell 包装它,但即使这样也无法显示涟漪效果。看起来我们需要像这样更深层次的嵌套处理。 - CopsOnRoad
@CopsOnRoad 好的,那不是这个问题的主题。 - Rémi Rousselet
1
@RémiRousselet 完全正确。但是我想也许有些微小的东西(某些属性)我没有注意到,你的评论可能会有所帮助。但无论如何,我非常感谢你的回答。 - CopsOnRoad
2
@CopsOnRoad 如果想要具有涟漪效果,您可能需要将Cardchild包装在InkWell中。在您的情况下,涟漪效果无法显示,因为它会被Card遮挡。 - Ovidiu Uşvat

80

Flutter提供了InkWell小部件。通过注册回调函数,您可以决定用户单击卡片时发生的操作(在Flutter中称为tap)。InkWell还实现了Material Design涟漪效果。

Card(
  child: new InkWell(
    onTap: () {
      print("tapped");
    },
    child: Container(
      width: 100.0,
      height: 100.0,
    ),
  ),
),

1
在我看来,墨水瓶应该放在卡片的外面 - forresthopkinsa
3
这取决于您想要实现什么效果。如果您希望卡片内部被"ink"填充,则应该在卡片内部放置InkWell。相反,如果InkWell包裹卡片,则卡片外部(但不是卡片内部)的区域(默认情况下为矩形)将被填充为“ink”。您甚至可以在卡片内外分别放置Inkwell-这样两个区域都会被填充为"ink"。 - nonbeing
我认为问题是要使整个卡片可点击,而不是卡片内部的100x100容器。 - Mahesh Jamdade
@nonbeing,明白了,有道理。 - forresthopkinsa
1
如果卡片具有非透明背景(color参数),并且您希望该颜色在悬停/轻触时更改,则需要将InkWell放置在Card内部。 - rjh
1
如果您的卡片不是矩形的,涟漪效果将超出卡片的边界。为了解决这个问题,请确保在您的卡片上添加clipBehavior属性,例如clipBehavior: Clip.hardEdge - Alex.F

35
我认为你可以除了使用GestureDetector之外,还可以使用InkWell,只需将卡片包装在 InkWell()小部件中。
InkWell(
  onTap: (){ print("Card Clicked"); }
  child: new Card(),
);

7
为了获得涟漪效果,我不得不将 InkWell 放入 Card 组件中。 - Bennik2000
5
Card(child: InkWell())更好。 - Rafael L R

17

您可以使用Inkwell并插入splashColor,当用户点击时,可以在卡片上使用选择的颜色创建回弹效果。这主要用于材料设计。

return Card(
  color: item.completed ? Colors.white70 : Colors.white,
  elevation: 8,
  child: InkWell(
      splashColor: "Insert color when user tap on card",
      onTap: () async {

      },
    ),
);

1
你能解释一下你的回答与其他推荐“InkWell”的回答有何不同吗? - barbsan
1
我之所以输入了这个答案,是因为其他答案中没有splashColor,在用户点击时,它可以在卡片上使用所选颜色创建反弹效果。 这主要用于Material Design。 - AlexPad
@AlexPad,回答非常到位。鉴于onTap()的快速转换,突出显示颜色可能是更好的选择。 - MwamiTovi

9

将卡片包装在GestureDetector小部件中,代码如下:

 GestureDetector(
    onTap: () {
      // To do
    },
    child: Card(
     
    ),
  ),

另一种方法如下:

InkWell(
    onTap: () {
      // To do
    },
    child: Card(),
  ),

7
在Flutter中,InkWell是一个响应触摸操作的材料(widget)。
InkWell(
    child: Card(......),
    onTap: () { 
        print("Click event on Container"); 
    },
);

GestureDetector 是一个用于检测手势的小部件。

GestureDetector(
    onTap: () { 
        print("Click event on Container"); 
    },
    child: Card(.......),
)

区别

InkWell 是一个 Material 组件,当接收到触摸时,它可以显示涟漪效果。

GestureDetector 是更通用的组件,不仅支持触摸操作,还支持其他手势。


2
最佳方法是将 ListTile 添加为 Card 的子元素。 ListTile 不仅包含 onTap 方法,还能帮助你让 Card 变得更有趣。
Card(
  child: ListTile(
    title: Text('Title')
    leading: CircleAvatar(
      backgroundImage: AssetImage('assets/images/test.jpg'),
    ),
    onTap: () {
      print('Card Clicked');
    },
  ),
),

除了手势检测之外,ListTile 有哪些功能是 Card 单独无法实现的? - Ian
@Ian 没有什么特别的,除了在制作卡片列表时遵循材料模式。虽然这很常见,但 Card 当然也可以在列表之外使用。 - jayjw

1

大部分答案都很棒,但我想分享我的方法,适用于想在卡片或列表项上创建/显示涟漪效果的人。

Card(
  child: TextButton(
    onPressed: ()=> ...,
    child: ListTile(
           title: Text('title'),
  ),
  ),
);

1
您也可以将卡片插入到TextButton中:
TextButton clickableCard = TextButton(child: card, onPressed: onCardClick, style: [...]);

这带来的优势是,您可以免费获得一些功能。例如,在Flutter Web中,您会获得鼠标悬停效果,并且光标会变成手形,以便用户知道他可以在那里单击。其他附加功能可以使用样式进行自定义。

1
在Flutter中,当点击“child”时执行某些操作:
代码:你的代码看起来像这样:
child: Card(------
------------
--------),

步骤1:将鼠标光标放在Card上,然后按下Alt+Enter(在Windows中)选择使用小部件包装

步骤2:将默认小部件更改为GestureDetector

最终代码:

child: GestureDetector(
onTap: YourOnClickCode(),
child: Card(------
------------
--------),
),

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接