1

I have this layout for my items of my listview:

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:padding="10dp">

    <ImageView
        android:id="@+id/cartIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginRight="10dp"
        android:onClick="addToCartClick"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/itemName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:layout_toRightOf="@id/cartIcon"
        android:text="Filé Mignon"
        android:textAppearance="@android:style/TextAppearance.Small"
        android:typeface="normal" />

    <TableLayout
        android:id="@+id/tableInfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/itemName"
        android:layout_toRightOf="@id/cartIcon"
        android:weightSum="3">

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/qtyText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Qtd"
                android:textAlignment="center"
                android:textAppearance="?android:attr/textAppearanceSmall" />

            <TextView
                android:id="@+id/priceText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Preço"
                android:textAlignment="center"
                android:textAppearance="?android:attr/textAppearanceSmall" />

            <TextView
                android:id="@+id/totalText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Total"
                android:textAlignment="center"
                android:textAppearance="?android:attr/textAppearanceSmall" />

        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/qty"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="2 Kg"
                android:textAlignment="center"
                android:textAppearance="?android:attr/textAppearanceSmall" />

            <TextView
                android:id="@+id/price"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="R$ 75,00"
                android:textAlignment="center"
                android:textAppearance="?android:attr/textAppearanceSmall" />

            <TextView
                android:id="@+id/total"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="R$ 150,00"
                android:textAlignment="center"
                android:textAppearance="?android:attr/textAppearanceSmall" />

        </TableRow>
    </TableLayout>

</RelativeLayout>

And for ImageView the onClick method:

android:onClick="addToCartClick"

The onClick fires properly when tap the ImageView but does not get the correct view.
I want to replace the image when onClick occurs, and it replaces, but not only to this ImageView. It replaces for several others. It seems random.
The code for onClick is at follows:

 public void addToCartClick(View view) {
    ImageView img = (ImageView) view;
    img.setImageResource(R.drawable.cart_add);
}  

Adapter code:

public class ShopListAdapter extends ArrayAdapter<ShopListItem> {

Context context;
int resource;
ShopListItem[] objects;

public ShopListAdapter(Context context, int resource, ShopListItem[] objects) {
    super(context, resource, objects);

    this.context = context;
    this.resource = resource;
    this.objects = objects;
}

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

    if (convertView == null) {
        // inflate the layout
        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        convertView = inflater.inflate(resource, parent, false);
    }

    // object item based on the position
    ShopListItem item = objects[position];

    // get the TextView and then set the text (item name) and tag (item ID) values
    TextView itemName = (TextView) convertView.findViewById(R.id.itemName);
    itemName.setText(item.itemName);

    TextView qty = (TextView) convertView.findViewById(R.id.qty);
    qty.setText(item.quantity + "kg");

    TextView price = (TextView) convertView.findViewById(R.id.price);
    price.setText("R$" + item.price);

    TextView total = (TextView) convertView.findViewById(R.id.total);
    total.setText("R$" + item.total);

    return convertView;
}

}

What am I missing?

ramires.cabral
  • 910
  • 4
  • 13
  • 28

5 Answers5

1

ListView item view is recycled by ListView.
You shoud set default image resource to ImageView in Adapter#getView.

EDITED You can use tag.

 public void addToCartClick(View view) {
    ImageView img = (ImageView) view;
    img.setImageResource(R.drawable.cart_add);
    ((MyAdapter.MyItem)img.getTag()).addedCart = true;
}  

And your Adapter class.

public class MyAdapter extends BaseAdapter {
    public static class MyItem {
        public boolean addedCart;

        public MyItem(boolean addedCart) {
            this.addedCart = addedCart;
        }
    }

    public List<MyItem> itemList = new ArrayList<>();
    public MyAdapter() {
        final ArrayList<MyItem> myItems = new ArrayList<>();
        // your list size
        for (int i = 0; i < 10; i++) {
            myItems.add(new MyItem(false));
        }
        this.itemList = myItems;
    }

    @Override
    public int getCount() {
        return 10;
    }

    @Override
    public Object getItem(int position) {
        return itemList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Inflate View

        imageView.setTag(getItem(position));
        if (((MyItem)getItem(position)).addedCart){
            imageView.setImageResource(R.drawable.cart_add);
        }else{
            imageView.setImageResource(R.drawable.default_image);
        }
        return view;
    }
}
takahirom
  • 1,934
  • 2
  • 12
  • 21
1

Take an boolean in ShopListItem class -

  public boolean isSelected; 

and then check in getView method and set its image according to this boolean, so when you will scroll list view image will set to that particular imageview you selected previously-

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

    if (convertView == null) {
        // inflate the layout
        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        convertView = inflater.inflate(resource, parent, false);
    }

    // object item based on the position
    ShopListItem item = objects[position];

    // get the TextView and then set the text (item name) and tag (item ID) values
    TextView itemName = (TextView) convertView.findViewById(R.id.itemName);
    itemName.setText(item.itemName);

    TextView qty = (TextView) convertView.findViewById(R.id.qty);
    qty.setText(item.quantity + "kg");

    TextView price = (TextView) convertView.findViewById(R.id.price);
    price.setText("R$" + item.price);

    TextView total = (TextView) convertView.findViewById(R.id.total);
    total.setText("R$" + item.total);

    ImageView img = (ImageView) view.findViewById(R.id.cartIcon);
    img.setTag(position);

    if ( objects.isSelected ){

       img.setImageResource(R.drawable.cart_add);
    }else{
        // you can set default image here
    }
  }

    return convertView;
}

and add this code-

 public void addToCartClick(View view) {
    object.get( Integer.parseInt(view.getTag()) ).isSelected = true;
    notifyDatasetChanged();
 }  
NehaK
  • 2,639
  • 1
  • 15
  • 31
0

You should define your onClick logic in getView method instead. You're defining a click listener for it but it doesn't know about the position yet. From getView, you can pass the position of the item to view the correct item

Edit: If you are going to change the row itself please follow this link

Community
  • 1
  • 1
ikbal
  • 1,844
  • 4
  • 26
  • 46
0

Are you overriding public boolean hasStableIds() to return true? What sounds like is happening is that some items in your ListView might have the same ID. If you are overriding public long getItemId(int position), make sure that the function cannot return the same long for different ListView items. You should also just set public boolean hasStableIds() to return false.

If that doesn't work, try removing android:onClick="addToCartClick" from your XML file and just add an OnClickListener in the public View getView (int position, View convertView, ViewGroup parent) function of your ListAdapter like this:

imageView.setOnClickListener(new View.OnClickListener() {
    void onClick(View v) {
        addToCartClick(imageView)
    }
});
kbrohkahn
  • 41
  • 2
0

Putting all your efforts together I came to solution:

My new getView with view holder pattern as suggested by @Mohamed:

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

    ViewHolder viewHolder;
    // object item based on the position
    final ShopListItem item = objects[position];

    if (convertView == null) {
        // inflate the layout
        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        convertView = inflater.inflate(resource, parent, false);

        viewHolder = new ViewHolder();
        viewHolder.itemName = (TextView) convertView.findViewById(R.id.itemName);
        viewHolder.qty = (TextView) convertView.findViewById(R.id.qty);
        viewHolder.price = (TextView) convertView.findViewById(R.id.price);
        viewHolder.total = (TextView) convertView.findViewById(R.id.total);
        viewHolder.img = (ImageView) convertView.findViewById(R.id.cartIcon);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    // get the TextView and then set the text (item name) and tag (item ID) values

    viewHolder.itemName.setText(item.itemName);

    viewHolder.qty.setText(item.quantity + "kg");

    viewHolder.price.setText("R$" + item.price);

    viewHolder.total.setText("R$" + item.total);

    //Here's the trick
    viewHolder.img.setTag(R.string.tag_adapter, this);
    viewHolder.img.setTag(R.string.tag_item, item);

    if(!item.finished)
        viewHolder.img.setImageResource(R.drawable.ic_launcher);
    else
        viewHolder.img.setImageResource(R.drawable.cart_add);
    //End Here's the trick
    return convertView;
}

And onClick method:

public void addToCartClick(View view) {
    ShopListItem item = (ShopListItem) view.getTag(R.string.tag_item);
    ShopListAdapter adapter = (ShopListAdapter) view.getTag(R.string.tag_adapter);

    item.finished = !item.finished;
    adapter.notifyDataSetChanged();
}  

And, as suggested by @ARMV, created a flag "finished" to check which image use. That way there is no need to put onClickListener inside the adapter. And setting tags with adapter and current item I can use more than one listview.
Also use of tags as suggested by Men Taka.
It Works pretty well.
Thank you all!

ramires.cabral
  • 910
  • 4
  • 13
  • 28