Hi want to create a custom cursor adapter so I can display an image with 2 lines of text. I have had some trouble understanding the custom cursor adapters but I do not understand how to add an imageview to be filled from the path in my database.
4 Answers
Will,
I've actually implemented something incredibly similar to what you are looking for. Here is my implementation.
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class ItemAdapter extends CursorAdapter {
private LayoutInflater mLayoutInflater;
private Context mContext;
public ItemAdapter(Context context, Cursor c) {
super(context, c);
mContext = context;
mLayoutInflater = LayoutInflater.from(context);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mLayoutInflater.inflate(R.layout.items_row, parent, false);
return v;
}
/**
* @author will
*
* @param v
* The view in which the elements we set up here will be displayed.
*
* @param context
* The running context where this ListView adapter will be active.
*
* @param c
* The Cursor containing the query results we will display.
*/
@Override
public void bindView(View v, Context context, Cursor c) {
String title = c.getString(c.getColumnIndexOrThrow(ItemDbAdapter.KEY_TITLE));
String date = c.getString(c.getColumnIndexOrThrow(ItemDbAdapter.KEY_DATE));
String imagePath = c.getString(c.getColumnIndexOrThrow(ItemDbAdapter.KEY_IMG));
int deletion = c.getInt(c.getColumnIndexOrThrow(ItemDbAdapter.KEY_DELETION));
int priority = c.getInt(c.getColumnIndexOrThrow(ItemDbAdapter.KEY_PRIORITY));
/**
* Next set the title of the entry.
*/
TextView title_text = (TextView) v.findViewById(R.id.item_text);
if (title_text != null) {
title_text.setText(title);
}
/**
* Set Date
*/
TextView date_text = (TextView) v.findViewById(R.id.item_date);
if (date_text != null) {
date_text.setText(date);
}
/**
* Decide if we should display the paper clip icon denoting image attachment
*/
ImageView item_image = (ImageView) v.findViewById(R.id.item_attachment);
item_image.setVisibility(ImageView.INVISIBLE);
if (imagePath != null && imagePath.length() != 0 && item_image != null) {
item_image.setVisibility(ImageView.VISIBLE);
}
/**
* Decide if we should display the deletion indicator
*/
ImageView del_image = (ImageView) v.findViewById(R.id.item_deletion);
del_image.setVisibility(ImageView.INVISIBLE);
if (deletion == 1) {
del_image.setVisibility(ImageView.VISIBLE);
}
}
}
XML just incase...
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/list_bg">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView android:id="@+id/item_text"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:lines="1"
android:scrollHorizontally="true"
android:ellipsize="end"
android:paddingLeft="2sp"
android:paddingTop="2sp"
android:textSize="18sp"
android:textStyle="bold"
android:shadowColor="#90909090"
android:shadowDx="1.0"
android:shadowDy="1.0"
android:shadowRadius="1.0"/>
<TextView android:id="@+id/item_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textColor="#FF808080"
android:paddingLeft="2sp"
android:paddingTop="2sp"/>
</LinearLayout>
<ImageView android:id="@+id/item_deletion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/deletion"
android:visibility="invisible"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:paddingRight="5sp"/>
<ImageView android:id="@+id/item_attachment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/attachment"
android:visibility="invisible"
android:layout_centerVertical="true"
android:layout_toLeftOf="@id/item_deletion"/>
</RelativeLayout>
This displays two rows of text and up to 2 images to the right of the text depending on certain conditions.
I hope this can give you a basis to work from!
Good luck :]

- 33,439
- 9
- 77
- 71
Adding images and text is not specific to CursorAdapter
; you use the same technique for any kind of adapter. You can create a layout for your row and inflate it inside your getView
method. The APIDemos sample project, contained in the Android SDK android-sdk-PLATFORM/samples/android-XY/ApiDemos
folder, does what you want. You can find the row definitons in list_item_icon_text.xml
. Here is copy of file content (w/o the license).
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView android:id="@+id/icon"
android:layout_width="48dip"
android:layout_height="48dip" />
<TextView android:id="@+id/text"
android:layout_gravity="center_vertical"
android:layout_width="0dip"
android:layout_weight="1.0"
android:layout_height="wrap_content" />
</LinearLayout>
Check what I have done:
BTW: CheckpointsView.getImageResId()
returns a valid drawable reference
public class CheckpointCursorAdapter extends ResourceCursorAdapter {
private int layoutType = 0;
public static final int BLOTTER = 1;
public static final int DAY = 2;
public static final int MONTH = 3;
public static final int OVERVIEW = 4;
public static final int LAYOUT_ID = R.layout.checkpoint_row;
public CheckpointCursorAdapter(Context context, int layoutType, Cursor cursor) {
super(context, LAYOUT_ID, cursor);
this.layoutType = layoutType;
}
@Override
public View newView(Context context, Cursor cur, ViewGroup parent) {
LayoutInflater li = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return li.inflate(LAYOUT_ID, parent, false);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView tvListText = (TextView) view.findViewById(R.id.txtCheckPoint);
Date dt = new Date(cursor.getLong(cursor.getColumnIndex(DatabaseHelper.KEY_CHECKPOINT)));
switch (layoutType) {
case BLOTTER:
tvListText.setText(dt.toLocaleString());
((ImageView) view.findViewById(R.id.imgCheckpointInOut))
.setImageResource(CheckpointsView.getImageResId(cursor.getCount()
- cursor.getPosition()));
break;
case DAY:
tvListText.setText(new SimpleDateFormat("HH:mm:ss").format(dt));
((ImageView) view.findViewById(R.id.imgCheckpointInOut))
.setImageResource(CheckpointsView.getImageResId(cursor.getPosition() + 1));
break;
case MONTH:
tvListText.setText(new SimpleDateFormat("MMM dd HH:mm:ss").format(dt));
((ImageView) view.findViewById(R.id.imgCheckpointInOut))
.setImageResource(CheckpointsView.getImageResId(cursor.getPosition() + 1));
break;
case OVERVIEW:
break;
}
}
}
And the XML just in case
<?xml version="1.0" encoding="utf-8"?>
<TextView android:id="@+id/txtCheckPoint"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="20dp" android:padding="8dp" android:textStyle="bold">
</TextView>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content" android:orientation="horizontal"
android:gravity="right" android:layout_weight="1"
android:layout_marginRight="8px">
<TextView android:id="@+id/txtTotalHours"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="20dp" android:padding="8dp" android:paddingRight="12dp">
</TextView>
<TextView android:id="@+id/txtHourBalanceRow"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="12dp" android:padding="8dp">
</TextView>
<ImageView android:id="@+id/imgCheckpointInOut"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/black_clock" />
</LinearLayout>
You can check the whole code at: http://code.google.com/p/droidtimesheet/

- 3,247
- 2
- 32
- 37
-
@ everyone thank you for all of your help. I got it figured out – waa1990 Mar 14 '11 at 16:36
Here is a great tutorial that I have used before to help with my custom list adapters. It sounds like it is doing the exact same thing you want to do. The tutorial shows how to build a custom list adapter with an image and two lines of text.

- 5,909
- 9
- 45
- 70
-
I noticed that the tutorial you linked is a bit **outdated**. It uses `ArrayAdapter` instead of `CursorAdapter`. Further, the layout file uses `LinearLayout` which can be replaced by a `RelativeLayout` to avoid one stack level. The better layout is mentioned in the [link](http://www.curious-creature.org/2009/02/22/android-layout-tricks-1/) that the author refers to. Further, some naming conventions are outdated, e.g. `android:id="@+id/android:empty"` instead of `android:id="@android:id/empty"`. – JJD Aug 01 '12 at 17:01
-
Thanks for pointing this out, this is the problem with technology tutorials... not much of a shelf life. – jbranchaud Aug 02 '12 at 02:06
-
@JJD Using array adapters is perfectly ok. If the data for the listview is in the form of an array, use an array adapter. If the data is in in the form of a cursor then use a cursor adapter. The layout should not be replaced by linearlayout. It should be removed all together as every layout is based on a framelayout as a starting point. – MobileMon Mar 22 '13 at 12:56