14

I have a listview defined by the following xml. I need to toggle the image in the list during runtime when the user clicks on any row. How can I achieve this? Any help is highly appreciated. Thanks

//list_item.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" 
android:id="@+id/img"
/> 
<TextView 
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:id="@+id/txt"
/>
</LinearLayout>
Vivek
  • 4,526
  • 17
  • 56
  • 69

5 Answers5

20

You can locate the item's img view by calling findViewById on the second parameter (which is the View of the clicked item) within the onItemClick handler:

public void onItemClick(AdapterView parentView, View clickedItemView, int pos, long id)
{
    ImageView imageView = (ImageView) clickedItemView.findViewById(R.id.img);
    // ...
}

EDIT: Be aware that Android reuses list item View objects (also called view recycling), so the toggle state of each item needs to be stored for later use. The toggle state of each item needs to be accessed whenever a list item view is bound to a list item for display.

For example, here is working example of an activity that toggles the image of each item on click:

import java.util.Arrays;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;

public class SO4539968TestCaseActivity extends Activity {
    private static final List<String> ITEM_TEXTS = Arrays.asList(new String[] {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13"});

    private boolean[] itemToggled;

    private class MyArrayAdapter<T> extends ArrayAdapter<T>
    {
        public MyArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) {
            super(context, resource, textViewResourceId, objects);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View itemView = super.getView(position, convertView, parent);
            ImageView imageView = (ImageView) itemView.findViewById(R.id.img);
            imageView.setImageResource(itemToggled[position] ? R.drawable.on : R.drawable.off);
            return itemView;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        itemToggled = new boolean[ITEM_TEXTS.size()];
        Arrays.fill(itemToggled, false);

        ListView listView = (ListView) findViewById(R.id.list_view0);
        listView.setAdapter(new MyArrayAdapter<String>(this, R.layout.list_item, R.id.txt, ITEM_TEXTS));
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> listView, View itemView, int position, long id) {
                itemToggled[position] = ! itemToggled[position];

                ImageView imageView = (ImageView) itemView.findViewById(R.id.img);
                imageView.setImageResource(itemToggled[position] ? R.drawable.on : R.drawable.off);
            }
        });
    }
}

The important parts to study are the onItemClick callback and the override of getView in MyArrayAdapter.

The getView method of the Adapter class is responsible for inflating the item layout. In this example, I call the getView method of the superclass to initially prepare the item view, but then I make sure to appropriately set the resource ID of the item's img view:

imageView.setImageResource(itemToggled[position] ? R.drawable.on : R.drawable.off);

See also: Developing Applications for Android – Gotchas and Quirks

Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193
  • Thank you so much. It worked for me. I was searching for this solution for a very long time, about a month. You saved me :D – Vivek Dec 27 '10 at 17:37
  • Now, I am able to change the source of the Imageview, but when I scroll below and come back again, the imageview is reset back to its previous source. Why is this happening? Can you help me? – Vivek Dec 27 '10 at 18:03
  • 1
    @Vivek: It sounds like a view reuse problem. Please see my updated answer because I have added a working example and have linked to an excellent blog post that describes Android's recycling of views. – Daniel Trebbien Dec 28 '10 at 00:48
  • @Daniel Trebbien thanks a lot. This works like magic to me.. I am using this for my imageview which I want to behave like radiobutton.. so how can I make other selected toggle to unselected on item click? plz show me a way to achieve this.. – Panache Aug 02 '11 at 17:40
  • @Panache: I am not sure what you are asking for. Do you want only one row to show the "selected" image? I.e., if item 1 is "selected", would clicking item 2 select that item *and* deselect item 1? – Daniel Trebbien Aug 03 '11 at 23:14
  • 1
    @Panache: The code is very similar. Instead of the `itemToggled` array, you would use an `int` member to store the position of the "selected" item. Then, inside `onItemClick` (or `onListItemClick` if using a `ListActivity`), update the `int` member and call `notifyDataSetInvalidated()` on the list view's `MyArrayAdapter` instance. I have working code if you need it. Just ask a new question and I will post it. – Daniel Trebbien Aug 04 '11 at 14:58
  • @Daniel Trebbien I solved this using your itemToggled[], thanks for your response. In case if required will post another question. One Quick question, I want to show images and text in a different list items. I am able to show the images but the text are not getting bind with the list. I want rows with images and different row for text. – Panache Aug 04 '11 at 16:06
  • @Panache: If you want something like http://imgur.com/2dkUZ where the image is on one line and the text on another (but both image and text are part of the same list item view), then you can use [`RelativeLayout`](http://developer.android.com/reference/android/widget/RelativeLayout.html). If you want two, different list item views—one for the image and another for the text—then one idea is to use something like AWT/Swing's `CardLayout`. A quick Internet search yielded: [Android UI Pattern - Workspaces](http://www.androiduipatterns.com/2011/06/android-ui-pattern-workspaces.html) – Daniel Trebbien Aug 04 '11 at 18:14
  • Hi guys, i am facing the same problems. i tried this answer but i am getting null pointer at itemtoggled array. can you please help me with a sample answer based on my stackoverflow question. http://stackoverflow.com/questions/17404273/listview-odd-even-rows-refresh-automatically-when-scrolling-down-or-selecting-an . thanks and regards – Dimitri Jul 04 '13 at 16:39
  • @Dimitri: I am not sure why `itemToggled` would be null. Can you double-check that the member variable is initialized in the onCreate() method? If you update your new question with the full code involving adapting this `itemToggled` array solution, I can take a look. – Daniel Trebbien Jul 07 '13 at 01:21
14
    listview.setOnItemClickListener(new AdapterView.OnItemClickListener(){

        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {
            ImageView imageView=arg1.findViewById(R.id.img);
            imageView.setImageResource(R.drawable.new_image);

        }

    });
Jett Hsieh
  • 3,159
  • 27
  • 33
1

I will generate dynamically the listview and then bind to the onclickitem event, in order to do the setimageresource as say by 'Kiril Kirilov'.

ykatchou
  • 3,667
  • 1
  • 22
  • 27
0

This can be done so easily, you need to just look at on the position of list item that was clicked by user. A well described complete demo code is as below_

 public class ChangeImageInListDynamically extends Activity {
/**
 * Adapter for your data. 
 */
ImageAdapter adpAR;
ArrayList<String> itemList;
ListView mListView;
ImageAdapter mAdapter;

/**
 * Indicate which item is currently selected.  
 * Its default selected item is '0' e.g., 1st item. 
 */
private int selectedPosition=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    itemList = new ArrayList<String>();
    for (int i = 0; i < 11; i++) {
        itemList.add("Item - "+i);
    }

    mListView = (ListView)findViewById(R.id.data_list);

    //Initialize your adapter
    mAdapter = new ImageAdapter(nChangeImageInListDynamically.this, itemList);

    //set adapter to your list.
    mListView.setAdapter(mAdapter);

    //set list click listener.
    mListView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> av, View view, int position, long id) {
            //your image that need to change dynamically.
            ImageView imageView = (ImageView) view.findViewById(R.id.select);

            //position of clicked item.  
            selectedPosition=position;

            //change image of respective image.
            imageView.setImageResource(R.drawable.selected);

            //notify your adapter to update your list.  
            adpAR.notifyDataSetChanged();
        }
    });

}

static class ViewHolder {
    TextView title;
    ImageView img;                  
}   

/**
 * Your ImageAdapter.
 */
public class ImageAdapter extends BaseAdapter {

    ArrayList<String> dataList;
    Context context;

    public ImageAdapter(Context context, ArrayList<String> arrayList) {
        this.context = context;
        this.dataList = arrayList;

    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return dataList.size();;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;

        final ViewHolder holder;
        Log.d("posiiton ImageAdapater : ",""+position);
        if (row == null) { 
            LayoutInflater inflater = ChangeImageInListDynamically.this.getLayoutInflater();
            row = inflater.inflate(R.layout.listrow, null);

            holder = new ViewHolder();
            holder.title = (TextView) row.findViewById(R.id.text);
            holder.img = (ImageView) row.findViewById(R.id.select);
            row.setTag(holder);
        } else {
            holder = (ViewHolder) row.getTag();
        }

        //set titel text.
        holder.title.setText(dataList.get(position));

        //Change Image of selected item dynamically.
             if(selectedPosition == position) {
                 //Item is selected.
                 holder.img.setImageResource(R.drawable.selected);

             }else{
                 //Other non-selected items.
                 holder.img.setImageResource(R.drawable.dis_selected);

             }

        return row;

    }

 }

}

I hope this will help to all :)

Rupesh Yadav
  • 12,096
  • 4
  • 53
  • 70
-1

Use

public void setImageResource (int resId);

method of ImageView class.

P.S. My previous answer seems incomplete, here is the whole solution:

ImageView imageView = (ImageView) this.findViewById(R.id.img);
                ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();
                imageView.setImageResource(R.drawable.new_image);
                imageView.invalidate();
Kiril Kirilov
  • 11,167
  • 5
  • 49
  • 74
  • Here the problem is getting the ImageView. How do I get the corresponding ImageView from the ListView ? When I do **ImageView iv = (ImageView) view;** in OnListItemClick metod i get class cast exception. – Vivek Dec 27 '10 at 16:26
  • Does this work - ImageView imageView = (ImageView) this.findViewById(R.id.img); – Kiril Kirilov Dec 27 '10 at 16:28
  • 1
    No. Because, suppose If I have 40 rows in my listview, All the images will hold the same ID (i.e. img). So we cannot get the handle of selected ImageView with unique ID. – Vivek Dec 27 '10 at 16:38
  • The ImageView ID is R.id.img, but the drawables can be with different IDs like R.drawable.image1, R.drawable.image2... – Kiril Kirilov Dec 27 '10 at 16:44
  • Ya. So If I change the source of the image corresponding to R.id.img all the rows in my list are going to get affected right? But I want to change the image in only one row.. – Vivek Dec 27 '10 at 16:51
  • Sorry for my misunderstood! I can't help you without the original source where you initialize the whole list. – Kiril Kirilov Dec 27 '10 at 17:00