What is the correct way to modify all child elements (not only the visible ones) of a listview.
I have an image which is set, by default, to visibilty gone. I wish to make it visible after the user clicks a button (for all items).
Thanks!
What is the correct way to modify all child elements (not only the visible ones) of a listview.
One thing to understand about a ListView is that not all of the list items are generated (inflated/populated) at any given time.
Suppose, for example, your list Adapter has 1000 items in it but the ListView can only display 10 at once. It would be a very bad waste of resources (e.g., memory) to create all 1000 list items.
Instead, only the 10 visible items are created and each time you scroll one off the top or bottom of the screen, the one which has disappeared is re-cycled by being passed as convertView into the Adapter's getView method.
getView (int position, View convertView, ViewGroup parent)
To do what you are asking you should extend whatever Adapter type you wish to use and override the getView method. In that method check if convertView is null or not. If it is, inflate your own instance of your list item layout. If it is not null then re-use the UI elements (TextView, ImageView etc).
To have all ImageView elements visible, use a global Boolean such as showImageView which will be toggled by the button press. Then use that in getView to decide whether or not to set the visibility of the ImageView.
See Adapter.getView(...)
Probably you should set the image visibility in your ListAdapter's getView() depending on some field value. Upon button clicking you change this field value and then you invoke ListAdapter.notifyDataSetChanged so the List View updates - getView then gets called and image changes because your field value has changed.
Inside the getView() of your adapter, you grab the ImageView and set its visibility to gone:
ImageView iv = (ImageView)convertView.findViewById(R.id.image_view);
iv.setVisibility(buttonClicked ? View.GONE : View.VISIBLE);
Then when users click on the button, set buttonClicked = true, and call notifyDataSetChanged() to refresh the ListView.
Related
I have an expandable list view with checkboxes. When i click a child, an alertdialog and i choose the quantity and then the textView of a child changes. BUT when i scroll down the list and this child disappers from view , the list forget changed textview and set the old one. What's the reason?
ListView (and its descendent ExpandableListView) does NOT create and store the views forever; instead it creates them on-the-fly as needed.
Imagine a scenario where you have a ListView with a list containing 1000 items; but the views for only any 5 items can be visible on the screen at a given time. Do you think that ListView would create and maintain 1000 different views on the screen? That would be a waste of memory, and might cause the UI to lag.
Instead, ListView internally calls getView() function to obtain the view for each item and shows it on the screen. It does this every time the item is brought into the screen display, and only for those many number of items which can fit into the screen at a given time (ListView handles these things internally so you do not have to worry about this)
All you need to do is set the text in the corresponding list item, and use this text to populate the textview in getView(). Maintain a text String and create some form of getText() and setText(String) methods in whatever Object type you are using as an Item.
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
......//initialize text view for this position
Item item = getItem(position);
textView.setText(item.getText());
.......
}
Once you set the text in the list item via alertDialog, Call notifyDataSetChanged() on the adapter to indicate that getView needs to be called again for all the views currently in display.
In your Listener, pass a reference to the adapter of the ListView. When you set the quantity in the alertDialog, just use
{
......
adapter.getItem(position).setText(quantityText);
adapter.notifyDataSetChanged();
......
}
The first line sets the text in the item; the second line tells the adapter that the information in the items have changed and it needs to create the views again.
I have built a GridView populated by an Adapter of RelativeLayouts that contains a top level ImageView. The ImageView is not displayed until the user taps the item, thereby creating a "selected" effect for the individual View. When the user taps a different item, I hide the selected item on the previously selected View.
This works fine, but I'm curious if there's a more native Android way to handle this situation. I'm not seeing any sort of setSelected() (ish) method but perhaps I'm overlooking something?
Any subclass of View should have a setSelected() method, which includes RelativeLayout. You should keep track of the selected position in your adapter, and then in your getView() method:
myRelativeLayout.setSelected(selectedPosition == position);
Which will work if you're using a selector that handles state_selected. For your method, you could just say:
myImageView.setVisibility(selectedPos == pos ? View.VISIBLE : View.INVISIBLE);
And when you register a click (in your OnItemSelectedListener or OnItemClickListener, or whatever you're using) just call your adapter's setSelectedPosition() method with the touched position, and then call your adapter's notifyDatasetChanged() method.
I have a problem with ListView which recycles views that are visible on the screen.
I can have up to 4 items in my ListView, they are all visible on screen.
After I update a property of an object in the ArrayList that the ListAdapter uses i call the notifyDataSetChanged() method of the list adapter.
This causes the ListView to recycle the views and to redraw it self.
The problem is that it's doing the recycling in a reverse order. so if i have a button on the first Listview item it will be in the second list view item after the notifyDataSetChanged().
I have getView that changes the convertView properties except for the button onTouchListener.
This is very problematic if i have a button that works with touch event (Like PTT button). its visible for sometime and then it becomes invisible :-(.
1. why does the ListView recycle items that are visible on the screen ? is this normal behaviour? why does it do in reverse order ?
2. what can I do to solve my issue ?
You should provide code for getview() method. And adding button to an item could cause problems when you are not using checks on adding button.
Rather than adding button you should include button in all items and just make visible invisible the button at specific position where you want.
Also make check of "null" for creating convertview in getview() method. This way it would not recycle/create views/item if they are not null.
My ListActivity is bound to an ArrayAdapter where I have overriden the getView() method. If I change the visibility of a widget in that method or modify the view's background color, those changes somehow get lost once that modified list item returns after being scrolled off the screen. In fact, some other view in the list is picking up the changes.
How do I get the modified view to look the same when it's redisplayed after scrolling?
Are you inflating a new view each time or making use of the convertView that is passed in?
Normally the Adapter tries to recycle views, only creating enough to provide smooth scrolling. The existing recycled views are passed in as convertView. You can either inflate and return a new view every time (expensive) or just re-setup the convertView (if it exists) based on position. If recycling you need to re-set all the view attributes, as there is no guarantee that the recycled view you get is the same one used for this position in the past.
It sounds like your bug is that you are not correctly re-setting all the attributes of the recycled view (convertView) to match the data for the current position.
I have a ListView in my android activity. And I populate the ListView by sub-class the BaseAdaptor (which returns a View in getView() method).
What if in my click listener of a button in a list item view, I
change the text of the TextView in the List item view
or
change the dimension of the list item view by adding/removing children of the list item view
What is an efficient to refresh my listView? I don't want the listView to re-trigger a query since there is no data change.
Thank you.
if you just change the content of your Children View, you have not more to do than TextView.setText(newText).
If you change the count of your ListView childrens, you have to call BaseAdaptor.notifyDataSetChanged()
I was about to suggest that you invalidate(), but you don't want to trigger a redraw, so I can only suggest that some form of global flag is your best bet. Set the flag, invalidate or redraw and query (and reset) the flag in OnDraw()