27

I want to create a listView of cards, but after reading this blog post goolge-plus-layout, I'm cards are a viable solution for a list of anything. The animation part seems too memory intensive to load say a listview with more than 40 elements simultaneously.

Is there a better way to achieve a cards UI in listView?

kyogs
  • 6,766
  • 1
  • 34
  • 50
Hick
  • 35,524
  • 46
  • 151
  • 243
  • I think you should review the getView method once again. Please share your implementation detail. – Rajnikant Jul 10 '13 at 12:58
  • a bit off tpoic but cards are not the default visual pattern to use for any list. They have a precise use among Google apps and should not be used randomly. – Teovald Jul 10 '13 at 12:58
  • 1
    I disagree that cards should not be used for a list. This is the quickly emerging pattern (what do you think G+ uses to back their timeline UI - it is a ListView with customized adapters). Card UI FTW! – Booger Sep 27 '13 at 00:43
  • this link will help you:http://www.technotalkative.com/lazy-productive-android-developer-4/ – Arash Jul 31 '14 at 16:21
  • is it possible to swap cards ?? – Nevaeh Aug 19 '14 at 10:55

5 Answers5

36

You can create a custom drawable, and apply that to each of your listview elements.

I use this one for cards in my UI. I don't think there is significant performance issues with this approach.

The drawable code (in drawable\big_card.xml) looks like this:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item>
        <shape android:shape="rectangle" >
            <solid android:color="@color/second_grey" />
        </shape>
    </item>
    <item
        android:bottom="10dp"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp">
        <shape android:shape="rectangle" >
            <corners android:radius="3dp" />

            <solid android:color="@color/card_shadow" />
        </shape>
    </item>
    <item
        android:bottom="12dp"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp">
        <shape android:shape="rectangle" >
            <corners android:radius="3dp" />

            <solid android:color="@color/card_white" />
        </shape>
    </item>


</layer-list>

I apply the background to my listview elements like this:

<ListView
    android:id="@+id/apps_fragment_list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:listSelector="@drawable/big_card" />

If you want to add this as a background to any View (not just a list), you just make the custom drawable that View's background element:

<TextView
        android:id="@+id/any_view"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/big_card" />
Booger
  • 18,579
  • 7
  • 55
  • 72
  • 2
    I'm really curious about what colours you use. – Navarr Sep 26 '13 at 20:19
  • 6
    I use #ff999999 #ffffffff #8c666666 (note the transparency on this color) – Booger Sep 27 '13 at 00:41
  • 2
    Thanks. This looks really nice. I'm using your layout in my app, though, and I changed second_grey to #ffeeeeee which is a lot lighter (more googley, imho) - and moved it to the background of my view so there's less overdraw. I wish I could figure out how to get that shadow without overdraw.. Google+ does it somehow.. – Navarr Sep 27 '13 at 18:46
  • 1
    Somehow I am missing something. Could you please explain how the drawable is applied to the list item layout? When I try your approach, the big_card drawable is only shown when a list item is pressed. – Philipp Nov 20 '13 at 14:24
  • Change that from android:listSelector to android:background – Booger Nov 20 '13 at 18:04
  • When I create a ListView, all of the items in the ListView end up on a single card... I'm very new to Android development, so I'm not understanding why it's putting all the text on a single card... – Bradley Swain Nov 29 '13 at 15:54
  • If you are using the ViewHolder pattern (you should, it is very important) - you are probably not recycling your view correctly. I would start with a ViewHolder tutorial, essential first step. Good luck. – Booger Nov 29 '13 at 18:18
  • Can you please edit your answer to show how do we add it to the listview elements as of now your answer states that how to add it complete listview..But I'm unable to get it worked for each individual listview element. – coder Dec 09 '13 at 11:09
  • You would just add the element as a background to your adapter, instead of the list itself. – Booger Dec 09 '13 at 14:10
  • 1
    I'm new to Android too, but I've read one note about this way (layer-list as CardView implementation) - 'I don't think the layer list is the way to go. Actually, it does the trick but it will lead to overdraw (draw twice the same pixel on your screen) which is not a good practice if you're a developer who's taking care of optimizing.' Is it true? Is there any way to solve dowuble-drawing? – Lonli-Lokli Mar 07 '14 at 11:50
  • I am not sure of another way to create this same effect (but I am open to suggestions, and will happily update this answer). – Booger Mar 07 '14 at 15:38
  • I don't think there is a different way to achieve this effect (including the drop shadow, which is important to me) without a Layer-list (and thus over-draw). – Booger Mar 14 '14 at 15:03
  • is it possible to swap cards ?? – Nevaeh Aug 19 '14 at 10:55
  • I'm considering using a 9-patch image for the gray background, white card and its drop shadow. It would minimize overdraw (all is 1 layer), but I wonder if it negatively affects performance/at which point it does. Any way to measure this that you know? cc: @Lonli-Lokli – siger Sep 18 '14 at 17:50
7

EDIT: Google provides a nice class called CardView. I didn't check it but it looks promising.

Here's the previous way, which also works fine (that's what I wrote before the edit) :

There is a nice tutorial here and a nice sample of it here .

in short , these are the files you can create:

listView definition:

android:divider="@null"
android:dividerHeight="10dp"
android:listSelector="@android:color/transparent" 
android:cacheColorHint="@android:color/transparent"
android:headerDividersEnabled="true"
android:footerDividersEnabled="true"

also this:

m_list.addHeaderView(new View(this));
m_list.addFooterView(new View(this));

res/drawable/selector_card_background.xml

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item
      android:state_pressed="true"
      android:drawable="@drawable/layer_card_background_selected" />

   <item android:drawable="@drawable/layer_card_background" />
</selector>

listView item :

res/layout/list_item_card.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:paddingLeft="15dp"
   android:paddingRight="15dp"
   android:descendantFocusability="beforeDescendants">

   <LinearLayout
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:paddingLeft="15dp"
      android:paddingTop="15dp"
      android:paddingBottom="15dp"
      android:paddingRight="15dp"
      android:background="@drawable/selector_card_background"
      android:descendantFocusability="afterDescendants">

      <TextView
         android:id="@+id/text1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"/>

      <TextView
         android:id="@+id/text2"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"/>

      <TextView
         android:id="@+id/text3"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"/>
   </LinearLayout>
</FrameLayout>

res/drawable/layer_card_background_selected.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#CABBBBBB"/>
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item
        android:left="0dp"
        android:right="0dp"
        android:top="0dp"
        android:bottom="2dp">
        <shape android:shape="rectangle">
            <solid android:color="#CCCCCC"/>
            <corners android:radius="2dp" />
        </shape>
    </item>
</layer-list>

res/drawable/layer_card_background.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#CABBBBBB"/>
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item
        android:left="0dp"
        android:right="0dp"
        android:top="0dp"
        android:bottom="2dp">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white"/>
            <corners android:radius="2dp" />
        </shape>
    </item>
</layer-list>
android developer
  • 114,585
  • 152
  • 739
  • 1,270
2

If all you want is a ListView that simulates the cards-look you can use a 9-patch as background for your listitems to make them look like cards. You can find a 9-patch and some more tips and explanation here: http://www.tiemenschut.com/simply-get-cards-ui-look/

TiemenSchut
  • 256
  • 1
  • 5
1

Add divider for the Listview item and padding :

 android:divider="@android:color/transparent"
    android:dividerHeight="1dip"

Add RelativeLayout into your LinearLayout for ListItem with some desired padding :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="100dp"
    android:orientation="vertical"
    android:padding="3dp" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"

        android:background="@drawable/rowshadow" >

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
...

Add Background to the listview item , like :

<?xml version="1.0" encoding="utf-8"?>
   <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item >
        <shape 
          android:shape="rectangle">
              <solid android:color="@android:color/darker_gray" />
              <corners android:radius="0dp"/>
        </shape>
     </item>
     <item android:right="1dp" android:left="1dp" android:bottom="2dp">
        <shape 
          android:shape="rectangle">
              <solid android:color="@android:color/white"/>
              <corners android:radius="0dp"/>
        </shape>
     </item>
   </layer-list>

Use https://github.com/elcrion/demo.cardlistview as an example. It is somehow close to google style

  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Dennis Meng Oct 24 '13 at 20:26
1

As "android developer" briefly mentions in his answer, the CardView class can be used to easily create card views.

Just wrap you UI widgets in a CardView element and you are ready to go. See the short introduction to the CardView widget at https://developer.android.com/training/material/lists-cards.html#CardView.

The CardView class requires a v7 support library, remember to add the dependencies to your .gradle file!

compile 'com.android.support:cardview-v7:21.0.+'
Community
  • 1
  • 1
zpon
  • 1,482
  • 1
  • 15
  • 21