I want a list inside a recycler view, I don't want nested scroll, what is the best approach for this?
What I am considering now is that dynamically add the inner list rows.
If that is the case, let the adapter hold the whole data for the inner list. The number of list rows in each row of the recycler view row is not fixed.
Please voice your opinions with pros and cons.
NB:- I dont have any code to post since I am working on this.
Inside List View you need to Disable scrolling.
i.e listview.setNestedScrollingEnable(false);
I'm dynamically adding Views to my items in a RecyclerView. These added Views should only be related to the item which they're added to, but I'm having a problem when I scroll. It seems the View is recycled and a new item is loaded, but those previously added views are still there, only now on the wrong item.
I'm assuming that it's just because the ViewHolder is being reused, so the added items show up again with a new item, when loaded.
How would one go about solving this?
This was an old question of mine. A bounty was placed on it, hence the surge of popularity and the multiple new and irrelevant answers.
As stated in both my comment to this answer and #CQM's comment below my original question, the answer is to override the onViewRecycled() method and perform any needed operations there. This method is called when a view is recycled, and any cleanup operations can be done here.
Documentation on this method can be found here.
In my case, it was a matter of deleting the invisible TextView's attached to the view. The text itself had been deleted, but the view remained. If many invisible TextView's accumulate on the view and aren't properly recycled when scrolling, the scroll will begin to lag.
You need to track what views have been added based on the backing data. I would probably add any necessary extra views in onBindViewHolder(), and remove any that might be present in onViewRecycled(). Then when you want to make one appear dynamically, change whatever variable you have tracking whether it should be visible, and call notifyItemChanged().
Based on this:
but those previously added Views are still there, but now on the wrong item.
Basically, as per the RecyclerView documentation, You have to reset the views everytime inside the onBindViewHolder() method,
so let say, you have a method that sets a view param if its your profile, so the code for the same goes as follows,
if (list.get(position).getId()==PreferenceManager.getUserID())
{
// do some view change here
setViewParam(true);
}else
{
// reset the view change here
setViewParam(false);
}
So what you're doing here is giving recycled ViewHolder a chance to reset.
Do comment if you need help!
You can use this! setItemViewCacheSize(int size)
Check here RecyclerViewDocumentation.
The offscreen view cache stays aware of changes in the attached adapter, allowing a LayoutManager to reuse those views unmodified without needing to return to the adapter to rebind them.
First of all, can you share some more code please?
Second, why would you want to dynamically add new views on fly? Why don't you use different VIEWTYPE or just have those view already on your layout and just make them visible/invisible or visible/gone? (I believe it will be more efficient this way).
Let me remind you something about RecyclerView, yes when user is scrolling viewHolder are being reused (few of them can be created, even more than it needs to fill the screen). So if it happened that you added some views on "item A" and user scroll to "item Z", that viewHolder can be reused for that "item Z", hence the show up of the previously added views.
How can you solve that?
Well always check on every items if you need to add new views, if yes add them if not already added, else always remove those views (if present) to return to default viewHolder state (or whatever you call it).
Hope this will help you.
Save Information by tags for items with new child each time the Add newView operation occur. (In shared preference for example)
Tag: create with item position onBindViewHolder.
...
SharedPreference sharedPref = getSharedPreference("text" + position, context);
SharedPreference.Editor editor = sharedPref.edit();
editor.putString("view", "ImageView");
...
when load Adapter get this value and put default as null.
I am not sure about its efficiency but i will work.
...
String viewType = sharedPref.getString("view", null);
//it will return ImageView
if you know some possible viewTypes for example always going to be ImageView & TextView so with some if statement it will be ok.
if(viewType.equals("ImageVIew")){
item(position).addView(new ImageVIew(context));
}
Good Luck
In your adapter class of your recyclerView,
in the onBindViewHolder method,
create another adapter and do the same methods for your new adapter.
The hierarchy will be,
mainRecyclerView -> item1(->childRecyclerView1) , item2(->childRecyclerView2), item3(->childRecyclerView3)
This way you can achieve what you want without wrong values to be viewed on wrong items.
You should take any Empty Layout like Linearlayout in your child item layout XML and then add views into that LinearLayout of your particular item in this way when you scroll List all of you child views which you have added to LinearLayout also scroll with that item .
I'm trying to achieve the effect of the footer for ListView but without using the addFooterView method of the ListView. My intention is to treat the last visible item of the list as a pinned footer. In my view I can achieve this by detecting the last visible item on the list and dynamically change it's layout. I did some research and I think I must extend the BaseAdapter class providing two types of items. One for ordinary item on the list indicating that adapter should inflate the item with ordinary layout. And the second one indicating that adapter should inflate the current item with layout of footer. I think i must override the onScroll method to detect the last visible item. And here are my questions. Should i call the getView method from the onScrollmethod ? Is it the proper way to implement such effect? Is it possible at all? I would be grateful for any suggestions.
Thank in advance.
And here are my questions.
Should i call the getView method from the onScrollmethod ?
no, you should never directly call getView(). Only classes that extend AbsListView call getView
Is it the proper way to implement such effect?
No. The proper way of doing it is calling addFooterView to your ListView object.
Is it possible at all? I would be grateful for any suggestions.
No, it's not possible. Using scroll listeners you will never be able to find out when the AbsListView is requesting the "last view". That's because ListView does not guarantee the order it queries for Views. That's specially true when you 1st set the adapter or call notifyDataSetChanged which causes the ListView to get the views in several points to be able to layout and measure stuff it needs.
The suggestion is to use the addFooterView method, that's the correct way of doing, that's why it's there.
I'd like to change my listView items dynamically. The algorithm goes like this:
1.I create the default view for my listView using adapter and show it to user. The list item contains Imageview, textview and another imageview which is invisible.
2.The data is beeing dowloaded in the meantime.
3. after my data is downloaded, I'd like to check whether my listview contains any of downloaded items. If yes, I want to make visible the previously invisible ImageView for this item.
Should I add some kind of method to my adapter, call it and then call invalidateViews(), notifyDataSetChanged(), or notifyDataSetInvalidated()? Or maybe there is some kind of standard way to find my adapter's item by Id or sth and then make visible the imageview for this item?
This list update operation is the only one left to implement for me.
Should I add some kind of method to my adapter, call it and then call invalidateViews(), notifyDataSetChanged(), or notifyDataSetInvalidated()?
Yes, exactly.
maybe there is some kind of standard way to find my adapter's item by Id or sth and then make visible the imageview for this item?
Above mentioned way is enough. There is no such standard or special way to do it AFAIK.
Read the Displaying Bitmaps Efficiently introduction and in particular the part about Handle Concurrency. This will give you all the information you need.
I'm working on creating a swipe-to-dismiss list view adapter. My basic methodology is to wrap the list item's view as the second view in a ViewPager and provide the necessary callbacks in the item change listener of the ViewPager. Through much pain I've got the View recycler working as intended, as well as ViewHolder and ViewBinder patterns implemented. I even managed to keep the ListView from taking over the touch events while the ViewPager is being scrolled without having to make a custom subclass of ListView (I can do it all from the Adapter).
Where I'm running into trouble is getting the selector and the OnItemClickListener to work. After looking at ListView's source it seemed that by overriding the ViewPager's hasFocusable() method to always return false (later on I'll pull this value from the child view) these things should have been reenabled. Unfortunately this is not the case. I've tried the setDecendantFocusability() workaround and I'm still stuck.
I'd like to avoid having to extend ListView if possible to provide the greatest amount of modularity. For similar reasons I don't want to add the selector to the ViewPager's background (if the dev changes the ListView's selector this wouldn't be reflected). Essentially I'm looking to make the ViewPager code transparent between the ListView and child View. Any ideas?
You are saying that you are making each list item a view pager, so that you can implement swiping to delete? If so... no no, this is not what view pager is for. First sorry it is just not intended to be used as an item in a list. Second it is for switching between views, not swiping to delete.
Unfortunately we don't have a sample code to show how to do this, but you can look at the platform's implementation of the notification pane or recent apps to get some ideas.