135

I just have a simple Card like new Card(child: new Text('My cool card')) and I want to be able to click anywhere on it to run some function, except there's no onPressed method for a Card. I could add a button to the bottom, but that's not ideal for this situation.

Anyone know how to make the whole card clickable?

Jus10
  • 14,519
  • 21
  • 52
  • 77

11 Answers11

236

Flutter use composition over properties. Wrap the desired widget into a clickable one to achieve what you need.

Some clickable widgets : GestureDetector, InkWell, InkResponse.

GestureDetector(
  onTap: () => ......,
  child: Card(...),
);
CiriousJoker
  • 552
  • 1
  • 7
  • 18
Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • How effective it is when there is List of gesture detector i am mostly interested in its usage in listview – silentsudo Apr 22 '18 at 09:34
  • That's the same stuff. – Rémi Rousselet Apr 22 '18 at 11:36
  • 3
    @RémiRousselet This works fine. But it doesn't show any ripple effect. I tried wrapping it in `InkWell` even that failed to show ripple effect. Seems like we need to do bit more nesting like [this](https://stackoverflow.com/questions/45424621/inkwell-not-showing-ripple-effect) – CopsOnRoad Oct 02 '18 at 10:43
  • @CopsOnRoad Well that's not the topic of this question – Rémi Rousselet Oct 02 '18 at 10:45
  • 1
    @RémiRousselet Absolutely right. But I thought maybe there is something tiny (some property) I was missing and your comment could have helped. But anyways, I really appreciate your answer. – CopsOnRoad Oct 02 '18 at 12:07
  • 2
    @CopsOnRoad To have ripple effect you may want to wrap the `child` of `Card` inside of a `InkWell`. The ripple effect can't be displayed in your case because it will be behind the `Card`. – Ovidiu Uşvat Sep 17 '20 at 13:54
80

Flutter provides the InkWell Widget. by registering a callback you can decide what happens when user clicks on the card (called tap in flutter). InkWell also implements Material Design ripple effect

Card(
  child: new InkWell(
    onTap: () {
      print("tapped");
    },
    child: Container(
      width: 100.0,
      height: 100.0,
    ),
  ),
),
Jossef Harush Kadouri
  • 32,361
  • 10
  • 130
  • 129
  • 1
    It seems to me that the Inkwell should probably be *outside* the Card – forresthopkinsa Apr 25 '19 at 18:59
  • 3
    @forresthopkinsa: that depends on what you want to achieve. If you want the Card to fill with the "ink", then the InkWell should be inside the Card. Instead, if the InkWell wraps the Card, then an area (by default, a rectangle) outside of the card (but not inside the Card) will fill with the "ink." You can even have an Inkwell each inside and outside the Card - whereby both areas fill with "ink." – nonbeing Jul 06 '19 at 16:53
  • I think the question was to make the entire card clickable and not the container of 100x100 inside a card – Mahesh Jamdade Jul 07 '19 at 02:35
  • @nonbeing sure, that makes sense – forresthopkinsa Jul 10 '19 at 20:29
  • 1
    If the card has a non-transparent background (`color` argument) and you want that colour to change on hover/tap, then the InkWell needs to be inside the Card. – rjh Aug 27 '22 at 11:27
  • 1
    If your card is not rectangular the ripple effect will go outside the border of the card. To address that make sure you add a `clipBehavior` to your `Card`. like `clipBehavior: Clip.hardEdge` – Alex.F Jun 13 '23 at 14:19
35

I think you can also use InkWell apart from GestureDetector just wrap the card inside InkWell() Widget

InkWell(
  onTap: (){ print("Card Clicked"); }
  child: new Card(),
);
barbsan
  • 3,418
  • 11
  • 21
  • 28
Mahesh Jamdade
  • 17,235
  • 8
  • 110
  • 131
17

You can use Inkwell and insert splashColor which, at the click of the user, creates the rebound effect with the chosen color, on the card .. This is mainly used in material design.

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

      },
    ),
);
AlexPad
  • 10,364
  • 3
  • 38
  • 48
  • 1
    Could you explain how is your answer different than others recommending `InkWell`? – barbsan Jul 18 '19 at 08:19
  • 1
    I simply entered this answer because in the others there was no splashColor which, at the click of the user, creates the rebound effect with the chosen color, on the card .. This is mainly used in material design – AlexPad Jul 18 '19 at 11:37
  • @AlexPad, answer is on point. And given the rapid transition of onTap(), a highlight color might be a better alternative. – MwamiTovi Jan 03 '20 at 09:49
9

Wrap a card in GestureDetector Widget like a below:

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

Another way is as follows:

InkWell(
    onTap: () {
      // To do
    },
    child: Card(),
  ),
Kalpesh Khandla
  • 758
  • 1
  • 9
  • 22
7

In Flutter, InkWell is a material widget that responds to touch action.

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

GestureDetector is a widget that detects the gestures.

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

Difference

InkWell is a material widget and it can show you a Ripple Effect whenever a touch was received.

GestureDetector is more general-purpose, not only for touch but also for other gestures.

Jitesh Mohite
  • 31,138
  • 12
  • 157
  • 147
2

The most preferred way is to add ListTile as Card child. Not only does ListTile contain the method onTap it also helps you in making Card interesting.

Card(
  child: ListTile(
    title: Text('Title')
    leading: CircleAvatar(
      backgroundImage: AssetImage('assets/images/test.jpg'),
    ),
    onTap: () {
      print('Card Clicked');
    },
  ),
),
Ganesh Bhosale
  • 2,000
  • 18
  • 21
  • What does ListTile enable that I can't do with Card alone (apart from gesture detection)? – Ian Apr 12 '21 at 17:15
  • @Ian nothing, besides conformity with material patterns when making a list of cards. While that is common, Card can certainly be used outside of a list. – jayjw Mar 06 '22 at 17:43
1

You also can insert a card into a TextButton:

TextButton clickableCard = TextButton(child: card, onPressed: onCardClick, style: [...]);

This brings the advantage, that you get some features for free. For example in Flutter Web, you get a mousover effect and the cursor changes to the hand so that ths user knows, he can click there. Other additional features can be customised using the style.

AzureIP
  • 338
  • 1
  • 10
1

Do something on tap/click of 'child' in Flutter:-

Code:-your code looks like:

child: Card(------
------------
--------),

Step1:- Put your mouse cursor on Card then, press- Alt+Enter(in windows) select wrap with widget.

Step2:- Change your default widget into GestureDetector.

final code:-

child: GestureDetector(
onTap: YourOnClickCode(),
child: Card(------
------------
--------),
),
ayush b
  • 99
  • 1
  • 2
1

Most of the answers are brilliant but I just want to share mine for the one who wants to make/show a ripple effect on Tap of card or list tile.

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

If you want a better UX while clicking the Card, I suggest you add InkWell as the Card's child. This gives the true Material 3 effect when clicking the Card. The code snippet below would do just that:

return Card(
  child: InkWell(
    borderRadius: BorderRadius.circular(12.0),
    onTap: () {},
    child: Column(
      children: [
        Text(
          'This is a Clickable Card!',
          style: TextStyle(fontSize: 20.0),
          ),
        Text('Try This Out!'),
      ],
    ),
  ),
);

As long as onTap is not null (having (){} is enough to make it not null), you will end up with the desired splash effect, AND you'll have a clickable Card. Also, the current Card widget in Flutter 3.7.10 comes with borderRadius: BorderRadius.circular(12.0). Therefore, it is necessary to add the same property to InkWell for a better UX.

Guy Mendel
  • 1
  • 1
  • 2