6

I want to create a very simple cursor custom cursor adapter to facilitate changing the colors of row items on click. Using the following code

private static int save = -1;

public void onListItemClick(ListView parent, View v, int position, long id) { 

    parent.getChildAt(position).setBackgroundColor(Color.BLUE);

    if (save != -1 && save != position){
        parent.getChildAt(save).setBackgroundColor(Color.BLACK);
    }

    save = position;                

}

I got the code from this thread https://stackoverflow.com/a/7649880/498449

I would have used a simple cursor adapter and placed the code in the onClick, but because the default list in the ListFragment reuses views, as you scroll multiple views are shown to be highlighted. Talking on IRC, it was suggested that I create a custom cursor adapter. However, I can't seem to locate the best practice how how to do this, and where the above code snippet would fit in. Could greatly appreciate the help.

public class AreaCursorAdapter extends CursorAdapter {
    private Context context;


    public AreaCursorAdapter(Context context, Cursor c) {
        super(context, c);
        // TODO Auto-generated constructor stub
    }

    @Override
public void bindView(View view, Context context, Cursor cursor) {
    TextView list_item = (TextView)view.findViewById(android.R.id.text1);
    list_item.setText(cursor.getString(cursor.getColumnIndex(INDICATOR_NAME)));

}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    LayoutInflater inflater = LayoutInflater.from(context);
    View v = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
    bindView(v, context, cursor);
    return v;
}

}

I've updated the cursor adapter with some code I found online. However, I have two problems. 1. I am using a cursor loader, so I don't have a "cursor" object to pass into the constructor. 2. I'm getting a warning from Eclipse that the constructor has been deprecated.

Community
  • 1
  • 1
Matthew McNaughton
  • 239
  • 1
  • 4
  • 16
  • in NewView you create a View with LayoutInflater.inflate, in bindView you set the content and background according to your selection int, in onclick you jsut change the selection int and tell the adapter that there has been a change to it's content. – zapl Mar 13 '12 at 19:20
  • @zapl could you show a code snippet. Also, I'm implementing this using a cursor loader, so I don't have a "cursor" object to pass to the constructor. – Matthew McNaughton Mar 13 '12 at 19:23
  • I don't have a snippet right now :( google probably has. With loaders do `adapter.swapCursor()` in `onLoadFinished`. – zapl Mar 13 '12 at 19:32
  • @zapl Unfortunately, I still haven't figured this out as yet. On the IRC channel it was told that I should modify the view in the BindView function and pass it the position from the ListFragment, but I'm not certain how to pass the parameter from the ListFragment onClick. – Matthew McNaughton Mar 14 '12 at 11:44
  • I've made up some code for u. Basically you just need to pass the selection somehow to your adapter which can then color the views the way you want them. At some place you might want to reset the selected position back to -1 – zapl Mar 14 '12 at 12:39

1 Answers1

19

You should be able to do it about that way:

class YourListFragment extends ListFragmentOrSomethingElse {
    private AreaCursorAdapter mAdapter;

    @Override    
    public void onCreate() {
        mAdapter = new AreaCursorAdapter(this, null);
        setListAdapter(mAdapter);
    }

    @Override
    public void onListItemClick(ListView parent, View v, int position, long id) { 
        mAdapter.setSelectedPosition(position);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        mAdapter.swapCursor(cursor);
        // should reset that here maybe
        mAdapter.setSelectedPosition(-1);
    }
}

public class AreaCursorAdapter extends CursorAdapter {
    private Context context;
    private int mSelectedPosition;
    LayoutInflater mInflater;

    public AreaCursorAdapter(Context context, Cursor c) {
        // that constructor should be used with loaders.
        super(context, c, 0);
        mInflater = LayoutInflater.from(context);
    }

    public void setSelectedPosition(int position) {
        mSelectedPosition = position;
        // something has changed.
        notifyDataSetChanged();
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        TextView list_item = (TextView)view.findViewById(android.R.id.text1);
        list_item.setText(cursor.getString(cursor.getColumnIndex(INDICATOR_NAME)));
        int position = cursor.getPosition(); // that should be the same position
        if (mSelectedPosition == position) {
           view.setBackgroundColor(Color.RED);
        } else {
           view.setBackgroundColor(Color.WHITE);
        }
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View v = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
        // edit: no need to call bindView here. That's done automatically
        return v;
    }

}
zapl
  • 63,179
  • 10
  • 123
  • 154
  • You are a life saver! I was able to get it to work with the above code. – Matthew McNaughton Mar 16 '12 at 02:58
  • where do i query the provider in listfragment ? – nia Nov 18 '12 at 18:08
  • @nia That would be using a `CursorLoader`. The query is inside `onCreateLoader` (not shown in above code) see http://helpmeco.de/2012/3/using-an-android-cursor-loader-with-a-content-provider for example – zapl Nov 18 '12 at 18:20
  • 1
    update helpmeco.de link http://responsiveandroid.com/2012/03/19/using-an-android-cursor-loader-with-a-content-provider.html – browep Dec 12 '14 at 22:01