So I have noticed something weird in Android List Adapters.
I have an adapter that is inflated with lets say template.xml, this template has a text view (TextView1 default: "hello"). In some cases TextView1 must have a value of "not now" and in other cases nothing (ie the default should be displayed). When the list contains all the default values everything is ok.
But as soon as in the GetView of a specific adapter I change it to "not now" it effects the others as well (not always if I close the activity and reopen it it may work).
What do you guys think?
Hard to say without your code, but this looks like a problem with reused views.
Make sure that you put back to default or to custom text every view in 'getView'. If you do not change it, it will leave the value that was previously set, which might not be the default one.
That behavior happens as intended.
The adapter recycles views through the use of convertView, which means that, for example, a view that you returned on position 10 can be reused on position 19.
For example:
If you set your position 10 to be "not now", and didn't change it back to the default value in your getView method in the position 19, it will keep the value you set for position 10.
Related
I've got a strange situation here.
There's a list view with a custom adapter. The view has a few different item types which are correctly used in getViewItemType. On just about every device and supported OS the getView method in the adapter is called without any weird behavior.
I know getView can be called many times and that isn't the issue. On a Nexus 5 and Nexus 6, however, getView is called twice for the same item type and passes a convertView of null.
The result is we end up creating two views for the same row in the list. It seems that one will actually get attached or added to the listview while the other isn't.
Any suggestions, or tips that might be causing this?
How do you know called twice for same item?
I ran the app with a debugger. It stopped on my breakpoint in getView multiple times (as expected) but two of the stops for the item passed null convertViews. It is a very small list, only four rows, each a different item type. They all show on the screen easily
You should check the position in getView() to make sure if called twice.
I suppose not because that the first time of each item view(convertView) always null, then you need inflate the view with item view layout and return it. While next time show the same view(even though for different item), the convertView will be not null, but you still need set views with value that according to the item position.
Hope you got!
I've got a GridView with a custom Adapter, displaying thumbnails of pictures to the user. I can select and deselect pictures (I use setAlpha(0.25) on the views to notify the user of the change), and that's all well and fine.
Now what I want to do next, is have a button on top of the gridview that clears the whole selection, i.e. call setAlpha(1.0) on all views that were changed. So far I can reset my elements in the adapter, and I can setAlpha to 1, but the view doesn't update unless I scroll it out of the display, and then get back to it, or notify the adapter of changes, which redraws all my views, which does not look too pretty if only one element was selected.
I already dynamically set and reset individual elements through the GridView's onClickListener, but can't do this for more. I even tried calling performClick on all selected items through my button, but again it only displays the changes after the views have been out of the screen and are shown again.
Here's how I simulate the clicks:
for (int i = 0; i < mAdapter.getCount(); i++) {
PictureForSelection tempPic = (PictureForSelection) mAdapter.getItem(i);
if (tempPic.isPicSelected()) {
//tempPic.setIfSelected(false);
gridview.performItemClick(mAdapter.getView(i, null, null), i, i);
}
}
EDIT:
Conclusion - don't simulate clicks like this :)
So now I skip click simulation and use this:
gridview.getChildAt(i).setAlpha((float) 1.0);
In general it does exactly what I wanted it to do, except for one case:
If I have for example 3 pictures selected, one is off screen, one is partly shown, and one is fully shown, the ones shown (even partially) don't update their views.
If all the selected pictures are displayed it works flawlessly, but if some are out of the display, the rest do not update until the adapter's getView() gets called by Android. Still, thanks #mmlooloo for getting me so far.
If anyone knows a way around this, please do share :)
After setting your alpha you can call imageview.invalidate(); this causes your imageview to redraw itself.
if notifyDataSetChanged() is not working you can try like this.
i'm not sure whether this works,
1.onclick of the button you set the gridView.setAdapter(null);
2. Then set a new CustomAdapter object to gridview with default values.
I have following code that works fine when my ListView is already rendered (eg. when fired by onClick events, etc.)
TextView tv = (TextView)list.getChildAt(position); //list is my ListView
if (tv!=null) {
tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
However, sometimes I need to apply this STRIKE_THRU_TEXT_FLAG flag to some items of ListView when activity is being restored (after rotation, restart...). If I try to run this code in onCreate or onStart methods then list.getChild(position) returns null because no ListView item is visible yet (in fact screen is black at this time and actual drawing seems to be done in some later function).
Is there any easy way how to get around this? Maybe getChild function is not the best for this case...Or would you override rendering function of the ListView to make it work (seems like overkill to me)? Thanks
Don't modify the view itself like that; modify the actual data object that represents that list item (for example, if your ListView is backed by an ArrayAdapter, this would be the array item for that list position). You could set a flag or property to denote that the item should be displayed differently, and then add some conditional code to your adapter's getView() method to display the text in the proper style based on the properties of that list item's object.
You can then let the view render itself accordingly the next time it's shown, or trigger the redraw yourself by calling notifyDataSetChanged() on the list adapter.
I need all of the other views in my arrayadapter to check their attributes and return to a default attribute at certain times
use case: listview items (a)(b)(c)(d) , when you touch (a) it's background turns black. This is done in the ontouchListener. But when you touch view (b) it's background turns black BUT (a)'s needs to turn back to the default which is not black
I dabbled around with recalling the arrayadapter at the end of the view.OnClickListener but the problem with this is that it also resets the scroll position of the view, so if this list was much longer - which it is - and user touched item (r) , then it would reset the list and put the user back at item (a) at the top
I was looking at notifydatasetchangedbut I am not sure how to use that and where it should work
insight appreciated
notifyDataSetChanged will do the job. You can call that at any time in your code and this will trigger the adapter to call getView for the visible list items again and so update their content. So basically the only thing you have to do is to update the list item states or information before calling that method.
I have an android-app with a listview in an activity. The listview has, if I call it so, three data states.
no data loaded from inet -> only one dummy item is visible, saying that data is loading;
data is loaded and shown in list;
one listitem is clicked and now shows more information for this listitem (so it is increased in its height).
On every state change (1 -> 2, 2 -> 3), I call notifyDataSetChanged() on this ListAdapater.
This causes the listview to scroll down to the last item. This is ugly in the first transition and even more ugly in the second because the clicked list item is now out of focus.
As I can see, this happens with a google g1 with android 1.6. An htc touch with the same sdk acts like desired (I will try to figure it out with some more devices).
To avoid this, I tried to read out getScrollY() and set this value back. but this returns 0. The reason for this return value I already found on stackoverflow in other questions.
Has anyone else seen this problem? Why does the listview scroll to the last item? It was mentioned that listview keeps track of the scroll position. but it seems that it does not in my case.
Or maybe I am calling the wrong refresh method? Is notifyDataSetChanged the correct one?
I believe you want:
listview.setTranscriptMode(ListView.TRANSCRIPT_MODE_DISABLED);