Skip to content

Instantly share code, notes, and snippets.

@iheanyi
Last active February 10, 2019 17:32
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save iheanyi/5774841 to your computer and use it in GitHub Desktop.
Save iheanyi/5774841 to your computer and use it in GitHub Desktop.
Google Now Cards Layout XML. list_item.xml can be customized to your heart's content . . . Also, you can implement the following with DragSortListView for swiping to delete, reordering, and whatnot.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#e5e5e5">
<ListView
android:id="@+id/cardListView"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="@null"
android:dividerHeight="0dp">
</ListView>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle"
android:dither="true">
<corners android:radius="2dp"/>
<solid android:color="#ccc" />
</shape>
</item>
<item android:bottom="2dp">
<shape android:shape="rectangle"
android:dither="true">
<corners android:radius="2dp" />
<solid android:color="@android:color/white" />
<padding android:bottom="8dp"
android:left="8dp"
android:right="8dp"
android:top="8dp" />
</shape>
</item>
</layer-list>
<?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="?android:attr/listPreferredItemHeight">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:background="@drawable/background_card">
<TextView
android:layout_gravity="left|center_vertical"
android:layout_width="fill_parent"
android:layout_weight="1"
android:textColor="@android:color/primary_text_light"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class NowArrayAdapter extends ArrayAdapter<String> {
private Context context;
private ArrayList<String> values;
private Typeface typeface;
private static Hashtable fontCache = new Hashtable();
private LayoutInflater inflater;
public class CustomListItem {
TextView descText;
}
public NowArrayAdapter(Context context, int resource, ArrayList<String> commandsList) {
// TODO Auto-generated constructor stub
super(context, R.layout.list_item, commandsList);
this.context = context;
values = new ArrayList<String>();
values.addAll(commandsList);
typeface = getTypeface(this.context, "fonts/Roboto-Light.ttf");
inflater = LayoutInflater.from(this.context);
}
static Typeface getTypeface(Context context, String font) {
Typeface typeface = fontCache.get(font);
if (typeface == null) {
typeface = Typeface.createFromAsset(context.getAssets(), font);
fontCache.put(font, typeface);
}
return typeface;
}
public View getView(int position, View convertView, ViewGroup parent) {
CustomListItem myListItem;
String myText = getItem(position);
if(convertView == null) {
convertView = inflater.inflate(R.layout.list_item, parent, false);
myListItem = new CustomListItem();
myListItem.descText = (TextView) convertView.findViewById(R.id.commandText);
myListItem.descText.setTypeface(typeface);
convertView.setTag(myListItem);
} else {
myListItem = (CustomListItem) convertView.getTag();
}
myListItem.descText.setText(myText);
//myListItem.descText.setTextSize(14);
return convertView;
}
}
@AKiniyalocts
Copy link

This is great, thank you very much! Where can I grab the background_card drawable?

@hanscappelle
Copy link

@AKiniyalocts it's listed, check background_card.xml ?

@iheanyi
Copy link
Author

iheanyi commented Jun 23, 2013

Yeah, it's background_card.xml as stated earlier. And you are quite welcome.

@GitTom
Copy link

GitTom commented Jun 25, 2013

Thanks for sharing this code!

It appears (to me) that the TextView in your list item layout (list_item.xml) is supposed to have the id 'commandText'. It is referenced in your NowArrayAdapter.java.

I also think it is better practise to declare your array as 'List' rather than 'ArrayList' given that you use them as List. (But I don't think you need to store your own copy of the array anyway, since the ArrayAdapter stores a copy itself.)

@mcapu
Copy link

mcapu commented Jun 25, 2013

I think you shouldn't create a new Typeface object every getView(). ¿Maybe only one in the constructor and saving it into a field? Also, in case there's several NowArrayadapter in the same application, you should implement a static constructor for it, like:

private static Hashtable fontCache = new Hashtable();

static Typeface getTypeface(Context context, String font) {
    Typeface typeface = fontCache.get(font);
    if (typeface == null) {
        typeface = Typeface.createFromAsset(context.getAssets(), font);
        fontCache.put(font, typeface);
    }
    return typeface;
}

And call it from the constructor. It will hugely reduce the memory allocation. I use this code from an external class, but you can add it to the adapter.

Edit: I forked the gist to show you these changes.

@iheanyi
Copy link
Author

iheanyi commented Jun 25, 2013

@mcapu - Thanks for the suggestion! I'll be sure to modify it, that's a better practice!

@mcapu
Copy link

mcapu commented Jun 26, 2013

You're welcome! By the way, I didn't say anything in the previous comment, but if you want to save a reference to the context (which is now rendered useless since you don't need it), you should call context.getApplicationContext().
This way you make sure you're not saving a reference to an Activity in case the adapter gets passed one in the arguments, and you will avoid those painful memory leaks. I suffered from them quite a lot.

@iheanyi
Copy link
Author

iheanyi commented Jun 26, 2013

@mcapu - Thanks once again! Jesus, I need to go and look at my old code and refactor a lot of it. I didn't even see what was going on under the hood, there are probably memory leaks all over the place.

@GitTom
Copy link

GitTom commented Jul 16, 2013

I disagree with the suggestion that the app context should be saved rather then the activity context. For the inflater, at least, it is necessary to use the activity context. I tried using the app context and this caused some wonky behaviour when inflating - it seems that you should always inflate on the activity context, and I suspect this could be taken as a more general lesson: use the activity context for anything related to the activity.

@iheanyi
Copy link
Author

iheanyi commented Jul 24, 2013

@GitTom - Duly noted, that makes sense . . . Thanks for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment