I created a RecyclerView that displays items.
Every X items, I have a native ad and beneath it a TextView with some title..
The user has an option to delete an item and then I use the following to do so:
public void removeAt(int position) {
items.remove( position );
notifyItemRemoved( position );
notifyItemRangeChanged( position, items.size() );
}
It does the job good and deletes the item and shifts the whole items one line up.
However, when I scroll over the position of the deleted item it still seems like the image of it is stuck and it shows it in the background between the lines of the RecyclerView as follows:
Any way I can make sure that the deleted item won't appear like this?
SOLUTION:
Setting the background of the title to white did the job.
The most common cause of this is the RecyclerView being inside a Fragment that's being inserted twice, often due to being unconditionally added in the Activity's onCreate when it's already there. Setting the background to white will cover up the issue, but not fix it.
Add some logging (logging when you set the adapter is a good place to do it) to check if your RecyclerView is actually getting added more times than you think.
Related
I'm making my first java android app and I'm having some issues with the RecyclerView.
I have a RecyclerView with a custom layout for each element.
I want to make that when I press the toolbar button, the Image Buttons inside EACH layout element inside the RecyclerView turn visible or invisible
This is the toolbar edit button code:
ArrayList<View> dest=new ArrayList<View>();
recView= findViewById(R.id.newListView);
recView.setItemViewCacheSize(0);
recView.findViewsWithText(dest,getString(R.string.onesingleuserlayout),View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
for (View oneUserLayout:dest)
{
oneUserLayout.findViewById(R.id.btnDelete).setVisibility(newVisibility);
oneUserLayout.findViewById(R.id.btnEdit).setVisibility(newVisibility);
}
It hides almost all the elements, but not every one of them. The ones shown behave correctly, and SOMETIMES the ones not showing don't.
I think that it is related to the cached items.
Remove this line, in order to permit caching:
recView.setItemViewCacheSize(0);
Here it's explained how it works (which may also explain, why caching is required).
Try to change your approach and instead of calling all those findView methods from outside the RecyclerView, implement a method on the adapter to change a boolean variable representing the visibility of the buttons and then call notifyDataSetChanged to force the layout manager to redraw all the visible itens and since all items reference the boolean variable, when new items are redrawn they will have the new visibility.
I'm going to reference the following question, because this person asked the same thing a month ago but nobody has answered him yet:
How to scroll the user at the exact position, which is somewhere between two views.?
When the user scrolls somewhere inside a recyclerview list and minimizes the app, then restores it from the bg - or goes into another activity/fragment and returns back to the recyclerview - I want the list to scroll to the exact same location the user was at. When I say the exact location I mean it has to be the exact same location - if I just tell the app to scroll to position X, then the topmost view will be at the top, but it won't be the same exact list state as the user had before. I need the list to look identical to the way it looked before the user left and returned. Is this possible, and if so, how?
My current code:
viewHolder.objectInTheList.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (recyclerViewInterface != null) {
FileAccessUtil.getInstance().setIntegerProperty("recyclerListPosition", position);
recyclerViewInterface.onRecyclerviewListEventOccured(position);
}
}
});
and then when I return to the activity I load that parameter from fileaccessutil and do:
recyclerlist.scrollToPosition(positionFromFileAccessUtil);
This solution is suboptimal because, as I mentioned before, it doesn't scroll the user to the exact identical screen position that he was at before.
Have you looked at RecyclerView.ScrollBy(x,y)?
ScrollBy(0,y) will scroll the RecyclerView in the same direction as it would if you were to move your finger up. It won't scroll to an absolute position, instead, it will just add pixels to the previous scroll position. To scroll in the opposite direction, simply use ScrollBy(0,-y). Notice that x is set to zero because you only want to scroll up/down.
Now, in order to achieve a complete solution, you will need to have a way to save the list's current scroll position. I did not test it, but I am pretty sure that RecyclerView.getScrollY() will always return 0. To overcome this, you will need to track the position yourelf by listening for scroll changes to the RecyclerView.
When you want to restore the scroll position, you can use your saved current position since the RecyclerView will, initially, have a scroll value of 0.
I've a ListView screen that is driving me mad.
Each row has three TextViews. The adapter is a custom ArrayAdapter that makes use of the view recycling mechanism: if the row is first requested, a new view is inflated, otherwise the recycled view is used. Everything works ok. I'm not showing it but for now assume it is correctly implemented.
This is how it looks normally:
There is a search button in the right upper corner of the screen. When clicked, every text view in the list is "cleared"! I've debugged the code and the textviews are there, the text is set and everything is ok except the text is barely or not shown. Here's a view dump taken with DDMS:
Looks like only the first letters of the text are shown. This only happens in certain devices, and only when the adapter's getView method returns the recycled view for the row, BUT only after pressing the search button, which makes the keyboard to show up (If i close it, the text is still missing). If I modify the getView method to always inflate every row this does not happen, but of course this is not an option since my list should be able to handle a large number of items.
Looks like a bug, but I need to do something about it.
I've also tested an alternative recycling mechanism based on a map (basically I put the view for each row in a map). Still the behavior is observed.
Device is a Samsung Galaxy SII running 4.1.2. Not happening in Galaxy SIII mini for instance.
Do you know what could be causing this glitch? Something related to the TextView's width?
Thanks in advance
I finally found the cause.
It was one of the TextViews in the adapter xml file. It was contained in a fixed-width LinearLayout. Its width was set to fill_parent, and changing it to wrap_content fixed the issue.
I am using a ListFragment with a custom adapter, which is used to inflate the views. The data is loaded via an AsyncTaskLoader once the fragment is created.
My problem is now that I want to scroll (not smooth scroll) to a certain position to show the last selected element, i.e. The fragment gets destroyed when I select an element and I want to show the same position in the list once the fragment is displayed again.
So creating the view and everything works fine, but I do not know where to add the getListView().setSelection(x) line to scroll to a certain position. I tried to invoke it after clearing and adding the elements to the adapter in Loader<?>.onLoadFinished() function, but that does not work, I get the following exceptoins:
java.lang.IllegalStateException: Content view not yet created
at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
at android.support.v4.app.ListFragment.getListView(ListFragment.java:222)
at fs.pokemon.effect.PokemonFragment.updateData(PokemonFragment.java:239)
at fs.pokemon.effect.PokemonFragment$2.onLoadFinished(PokemonFragment.java:129)
...
My question is: Is there a function/callback so I get notified, when the ListView has finished updating its content? Or how else can I scroll the View to a position after the content has loaded?
Thanks to pskink comment I tried it again and noticed that the exception does not occur in setSelection() but rather in getListView() - I though my loader would reload data after the view was created, but instead it used the cached results, so onLoadFinished() was actually called, before the initialization of the fragments view was finished, thus causing an exception.
The correct way to do it is to determine the position in onLoadFinished() and then override the fragments onViewCreated() and execute getListView().setSelection(curPosition) there.
Probably also the case that the loader cleared its cache and the onLoadFinished() will be called after the onViewCreated() method has to be considered, but so far it works fine.
Set the transcript mode and stackfromBottom for the listview while your listfragment activity is created. Now every time the listview is updated it will be scrolled to bottom to the latest item.
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListView().setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
getListView().setStackFromBottom(true);
}
I have a GridView which is scrollable: only some of the items will be displayed and only after scrolling down the GridView. We can see the other items. The problem is, I am setting the tags for all the items in the GridView, but by tracing the LogCat I came to know that it is not accepting to set the tags for the non-visible items in the GridView(I mean the items which are inside the grid, but at that time are not on the screen)
Before scrolling:
After scrolling:
Only after scrolling down the other items the tags are applied.
How can I set the tags for all the items of the grid, even if they are on the screen or off the screen?
Your problem is that you set the Tag in the getView method and this method is only called by the framework when the view need to be displayed.
Don't know exactly what you need to do with the view tag, but I think that instead of trying to get the data from a non-displayed view, you must get it from your ImageAdapter (ia.imageid[]).
EDIT:
To answer more preciselly to your question:
How can I set the tags for all the items of the grid, even if they are on the screen or off the screen?
As soon as the view doesn't always exists when it is not displayed: you cannot do it.
I suggest you to explain why you need those tags... may be you can use an alternative solution than view tag to accomplish your final needs.
Anyway, if you really need to have tag on view that aren't displayed yet:
Initialize a view array in onCreate method.
Populate this array with all your views (and set the tag)
modify getView method of your adapter to return the view from your array of view instead of creating the view.
Please note that I don't recommend this solution since it will consume more resources.
Finally myself i got the solution for my question.Thank you for all who gave their valuable suggestions.
Thank you #ben75
i checked the position of present clicked item and then applied the tag so if the user want to select the item which is presently not on the focus he has to scroll the grid and then have to select the item and then only the tag will be applied.