What's my Goal?
I need to update a nested Recycler View and all it's content, if a Switch changes it state (isChecked true/false) AND any other Item within the RecyclerView has the Same Category, then Update each of the Item's with the same Category to Disable the Switch. I need to disable the Switch Button, to prevent the User from selecting more than 1 Item of the same Category.
What's the issue?
My nested Recycler View will update my RecyclerView correctly, if the RecyclerView get's initially loaded, displayed and if I don't scroll even a nano-centimeter. But if I scroll the RecyclerView, nothing will update anymore... sometimes it does update the WRONG RecyclerView and only 1 Item... so no matter what Category I switch the (isChecked) to 'true', it will update 1 Item in a different RecyclerView (Everytime the same Item, which I checked before I started scrolling)
How is it implemented so far?
I have a RecyclerView which has an TextView on Top and a nested RecyclerView beneath it. This Nested RecyclerView has an Item, which basically consists of an Id, CategoryType, Text and CreationDate.
I'm using DiffUtil to do all the hassle for me (notifyDataSetChanged, notifyItemInserted... etc).
val diffUtil = CategoryDiffUtil(_categoriesWithinRecyclerViewAdapter, inNewCategories)
val diffResult = DiffUtil.calculateDiff(diffUtil)
diffResult.dispatchUpdatesTo(this)
I'm sending a new List of Categories to the "setData" functionallity within the FirstLevel RecyclerView, which calls each Nested RecyclerView's "setData" functionallity with the Categories for the Day. To know, which Item's Switch needs to be disabled, I store the Selected Category-Type in a List within the Nested RecyclerView where I recently Checked (Switch.isChecked == true) a Category. Every FirstLevel RecyclerView has an List of Reference to Adapters of the Nested RecyclerView beneath him. This is how I'm able to call "setData" or generally update the Nested RecyclerView (See Code for adding Adapter to FirstLevel RecyclerView to update beneath Nested RecyclerViews later)
if(_adapters.isEmpty() || !_adapters.any { it.first.contentEquals(inNewCategories.getCreationDate()) }){
_adapters.add(Pair(inNewCategories.getCreationDate(), _adapter!!))
}else if(_adapters.any { it.first.contentEquals(inNewCategories.getCreationDate()) }){
_adapters.removeIf { adapter -> adapter.first.contentEquals(inNewCategories.getCreationDate()) }
_adapters.add(Pair(inNewCategories.getCreationDate(), _adapter!!))
}
What have I tried to fix my Issue?
Tried to use nestedRecyclerViewAdapter.notifyDataSetChanged(), but it didn't help (does have the same issue mentioned in "What's the issue?").
Added Logs to ensure, that the Nested RecylcerView Adapter's are correctly stored and replaced. Ensure that the DiffUtil get's triggered if something changed (It does, and it know's exactly which item's needs to be updated)
I Tried to use Compose LazyColumn + StickyHeader to see if this changes something. But I'm still to inexperienced with it, that's why it was running far slower than my Nested RecyclerView and I gave up (for now) on using it (compose).
Not sure if I explained any crucial detail, but I hope someone could help me.
Related
I am using recycler view(https://github.com/thoughtbot/expandable-recycler-view) to display list of sections and subsections. It is working just fine. But when I am trying to update the list with live data and using :- recyclerView.adapter = adapter by creating adapter everytime when live data updates. But when data is updated, it collapses the each section regardless it was expanded already. I want to keep state of list as it was when updating it. Can someone tell me how to achieve this or any other way of updating the adapter that keep the state of list same(if it is expanded, remain expanded, collapsed, remain same). Thanks in advance.
Here is the code of how I am updating the list and notify.
adapterlist = newlist;
and then I call notifyiteminserted(postionofinsertion);
I am using setReverseLayout(true) to make it a chat like RecyclerView;
My RV stays still, no change is visible. I need to scroll down to see the item.
Expectations -> If I am at the last item then item insert animation should happen and I am beyond the last item then nothing should happen.
notifyiteminserted(0) is not working. There is no change in the layout and di have to scroll down.
If I use notifyiteminserted(2 or 4) it works the animation is showing.
I want to catch a vertical swipe in an horizontal RecyclerView. Each item is simply a CircleImageView.
I found many resources on internet (like Drag and swipe with RecyclerView, Android - Swipe to delete RecyclerView) but those solutions ends deleting the item. I don't know if the term swipe requires also that the item is deleted or not.
What I want to achieve is to catch the swipe action on an item in the RecyclerView, but without delete the item itself from the RecyclerView.
I think that a good idea is to override the method onChildDraw() like suggested here: How to detect if Recyclerview item is being swiped?, but I can't understand how to achieve the behaviour I want.
My idea is: while the user swipes an item, the item itself moves in that direction; when the user end the touch event, the item has to come back to the original position (maybe changing the background color).
EDIT 1:
How to have swipe to delete and swipe to archive in two colours in Recyclerview Android probably can help, but it doesn't achieve the behaviour that I need. The item has to come back to the original position.
Your RecyclerView has RecyclerView.Adapter attached to it. The adapter determines what information that the RecyclerView can see and display. So, if item number 10, out of a 100-item backing array (managed by you) is swiped, the adapter can report that the array now contains 99 items and not ever present the swiped item to the RecyclerView. That way the item appears to be deleted but is maintained internally and still accessible programmatically. How you manage that internal state is up to you and dependent upon your implementation.
If, however you want to not remove the item from the screen but just change its appearance, I think that you would need to look at the method onItemDismiss that actually removes the item and notifies the adapter of the data change.
public void onItemDismiss(int position) {
mItems.remove(position);
notifyItemRemoved(position);
}
It is here that you would make the change. The item would stay in the adapter. You would also need to flag that position as "swiped" in case the view holders are recycle so you can maintain the visual "swiped" state.
public void onItemDismiss(int position) {
// Change background color, etc.
}
Take a look at code that has a "swipe to delete" function with "undo" for some ideas. Here is an example with a dialog that is called before deletion actually occurs if "Cancel" is clicked. There are many other examples of "undo" available. What you are trying to do can be considered to be an immediate and implicit "undo" with a visual change to the background.
If you want to have the item move back into position after a swipe, the following should work:
public void onItemDismiss(int position) {
notifyItemChanged(position);
}
I have a RecyclerView and one item row needs to be updated like every second (SeekBar). So I call NotifyDataSetChanged once I update the data in the list. UI gets updated but the issue is that the RecyclerView scrolls so that this particular item is either at top or bottom of the screen.
I don't want RecyclerView to scroll.
// Update Data
mData.set(mData.indexOf(cardData), cardData);
// RefreshView
refreshView() {
runOnUiThread(new Runnable(){
notifyDataSetChanged();
}
);
You can update one item using notifyItemChanged(position); and u wont update all data in adapter, you will update only certain item
It's better to use the other notify methods from the RecyclerView.
For your usecase only swap out one item in your Adapter instead of all items and use notifyItemChanged(position).
This will be faster, the View won't scroll and if you ever will add an animation this will only work if you don't use notifyDataSetChanged
I got it working. I was having a card view above the recycler view.I just removed it. Now the whole screen is a recyclerView and I cannot see any auto scrolls.
I have vertical RecyclerView for scrolling group of items and horizontal RecyclerView in each ViewHolder in order to scrol items inside of these groups. They are populated from database. Whenever item content is changed (user tap something or new data come from network) it is written to database and then notifyDataSetChanged() is called for the group cursor. I check if it is the same group in onBingViewHolder() and update items only if it is. But horizontal RecyclerView is scrolled anyway to the first item.
How could I prevent this behavior and why does it happens ?
BTW I'm writing result of this check in 'onBindViewHolder()` to the log and I can see that it is the same item.
Thanks.
RecyclerView creates new ViewHolder in order to perform animation. setItemAnimator(null) solved my problem.