ListView custom adapter, strange ImageView behavior

I have a custom ListView Adapter with which I create rows for a list. My problem is that it does not seem to distinguish ImageView s from each other. It seems like a random selection of ImageViews to get stuck in place as I scroll up and down. Text information (omitted from this fragment) is not interrupted. It works as you would expect.

Here is the corresponding method of my Adapter :

  public View getView( int position, View convertView, ViewGroup parent ) { View v = convertView; if( v == null ) { LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate( R.layout.generic_row, null ); } // find the image ImageView favImage = (ImageView)v.findViewById( R.id.toggle_favorite ); // when clicked... favImage.setOnClickListener( new OnClickListener() { @Override public void onClick( View v ) { // make the gray star a yellow one int newImage = R.drawable.ic_star_yellow_embossed; ((ImageView)v).setImageBitmap(BitmapFactory.decodeResource(getContext().getResources(), newImage)); } }); return v; } 
+4
source share
2 answers

This behavior appears due to the fact that the ListView processes row representations when scrolling the list up and down, and because of this you get the rows that the user produced (the image was changed), the image was unmodified in the image. To avoid this, you need to somehow save the ImageView status for each row in the list and use this status to configure the correct image in the getView() method. Since you did not say exactly how you implemented your adapter, I will show you a simple example.

First of all, you must save your ImageView statuses. I used ArrayList<Boolean> as a member of the user adapter, if the position (corresponding to the position of the line in the list) in this list is false , then the image is the default, otherwise if it is true , then the user clicked it, and we need to put a new image:

 private ArrayList<Boolean> imageStatus = new ArrayList<Boolean>(); 

Initialize this list in your custom adapter constructor. For example, if you added a list of something to your adapter, you should make your imageStatus size of this list and fill in false (default status / start):

 //... initialize the imageStatus, objects is the list on which your adapter is based for (int i = 0; i < objects.size(); i++) { imageStatus.add(false); } 

Then in your getView() method:

 View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater) getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.adapters_adapter_with_images, null); } // find the image ImageView favImage = (ImageView) v .findViewById(R.id.toggle_favorite); // Set the image bitmap. If the imageStatus flag for this position is TRUE then we // show the new image because it was previously clicked by the user if (imageStatus.get(position)) { int newImage = R.drawable.ic_star_yellow_embossed; favImage.setImageBitmap(BitmapFactory.decodeResource( getContext().getResources(), newImage)); } else { // If the imageStatus is FALSE then we explicitly set the image // back to the default because we could be dealing with a // recycled ImageView that has the new image set(there is no need to set a default drawable in the xml layout) int newImage = R.drawable.basket_empty; //the default image favImage.setImageBitmap(BitmapFactory.decodeResource( getContext().getResources(), newImage)); } // when clicked... we get the real position of the row and set to TRUE // that position in the imageStatus flags list. We also call notifyDataSetChanged //on the adapter object to let it know that something has changed and to update! favImage.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Integer realPosition = (Integer) v.getTag(); //get the position from the view tag imageStatus.set(realPosition, true); //this position has been clicked be the user adapter.notifyDataSetChanged(); //notify the adapter } }); // set the position to the favImage as a tag, we later retrieve it // in the onClick method favImage.setTag(new Integer(position)); return v; } 

This should work if you do not plan to dynamically change the list (delete / add lines), otherwise you will have to take care to change this imageStatus list to reflect the changes. You did not say what your row data was, another approach (and the right one if you plan to do something if the user clicks on this image (in addition to changing it)) is to include the image status in the row data model. In this regard, here are some lessons:

Android ListView Advanced Interactive or Commonsware-Android Excerpt (Interactive Strings)

+3
source

you need to determine the default image immediately after searching for the link:

 // find the image ImageView favImage = (ImageView)v.findViewById( R.id.toggle_favorite ); //setting to default favImage.setImageResource(R.drawable.default_image); // when clicked... favImage.setOnClickListener.... 

you need to do this because as soon as the image is resized and you scroll through the ListView, it will reappear because the ListView is processing the views of the elements. So you need to define it in getView in order to use the default image when scrolling through the list

+2
source

Source: https://habr.com/ru/post/1402021/


All Articles