Drag and drop in Recyclerview using itemTouchViewer without affecting the animation
I am implementing onDragDrop method in the adapter class.
public boolean onDragDrop(int fromPosition, int toPosition) {
Collections.swap(list, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
if (fromPosition < toPosition) {
notifyItemRangeChanged(fromPosition, list.size());
} else {
notifyItemRangeChanged(toPosition, list.size());
}
return true;
}
The problem I am facing is when onDragDrop method is implemented, the animation is not good; there's a trace of elements before being replaced. I understand that for drag and drop, just notifyItemMoved method is enough, and with that, the animation is perfect. The reason I am implementing notifyItemRangeChanged is that after drag and drop, I want the data to get refreshed.
I went through a lot of StackOverflow posts and tried implementing the suggestions, but nothing worked. Thanks for your help.
java android android-recyclerview
add a comment |
I am implementing onDragDrop method in the adapter class.
public boolean onDragDrop(int fromPosition, int toPosition) {
Collections.swap(list, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
if (fromPosition < toPosition) {
notifyItemRangeChanged(fromPosition, list.size());
} else {
notifyItemRangeChanged(toPosition, list.size());
}
return true;
}
The problem I am facing is when onDragDrop method is implemented, the animation is not good; there's a trace of elements before being replaced. I understand that for drag and drop, just notifyItemMoved method is enough, and with that, the animation is perfect. The reason I am implementing notifyItemRangeChanged is that after drag and drop, I want the data to get refreshed.
I went through a lot of StackOverflow posts and tried implementing the suggestions, but nothing worked. Thanks for your help.
java android android-recyclerview
What do you mean bythere's a trace of elements before being replaced
? Do you mean that the items inside the range passed tonotifyItemRangeChanged()
flicker, or something else?
– Ben P.
Jan 2 at 22:55
@BenP. Yeah. In both the cases, the toPosition item is flickering.
– Sethuraman Srinivasan
Jan 2 at 23:04
add a comment |
I am implementing onDragDrop method in the adapter class.
public boolean onDragDrop(int fromPosition, int toPosition) {
Collections.swap(list, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
if (fromPosition < toPosition) {
notifyItemRangeChanged(fromPosition, list.size());
} else {
notifyItemRangeChanged(toPosition, list.size());
}
return true;
}
The problem I am facing is when onDragDrop method is implemented, the animation is not good; there's a trace of elements before being replaced. I understand that for drag and drop, just notifyItemMoved method is enough, and with that, the animation is perfect. The reason I am implementing notifyItemRangeChanged is that after drag and drop, I want the data to get refreshed.
I went through a lot of StackOverflow posts and tried implementing the suggestions, but nothing worked. Thanks for your help.
java android android-recyclerview
I am implementing onDragDrop method in the adapter class.
public boolean onDragDrop(int fromPosition, int toPosition) {
Collections.swap(list, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
if (fromPosition < toPosition) {
notifyItemRangeChanged(fromPosition, list.size());
} else {
notifyItemRangeChanged(toPosition, list.size());
}
return true;
}
The problem I am facing is when onDragDrop method is implemented, the animation is not good; there's a trace of elements before being replaced. I understand that for drag and drop, just notifyItemMoved method is enough, and with that, the animation is perfect. The reason I am implementing notifyItemRangeChanged is that after drag and drop, I want the data to get refreshed.
I went through a lot of StackOverflow posts and tried implementing the suggestions, but nothing worked. Thanks for your help.
java android android-recyclerview
java android android-recyclerview
asked Jan 2 at 22:50
Sethuraman SrinivasanSethuraman Srinivasan
333618
333618
What do you mean bythere's a trace of elements before being replaced
? Do you mean that the items inside the range passed tonotifyItemRangeChanged()
flicker, or something else?
– Ben P.
Jan 2 at 22:55
@BenP. Yeah. In both the cases, the toPosition item is flickering.
– Sethuraman Srinivasan
Jan 2 at 23:04
add a comment |
What do you mean bythere's a trace of elements before being replaced
? Do you mean that the items inside the range passed tonotifyItemRangeChanged()
flicker, or something else?
– Ben P.
Jan 2 at 22:55
@BenP. Yeah. In both the cases, the toPosition item is flickering.
– Sethuraman Srinivasan
Jan 2 at 23:04
What do you mean by
there's a trace of elements before being replaced
? Do you mean that the items inside the range passed to notifyItemRangeChanged()
flicker, or something else?– Ben P.
Jan 2 at 22:55
What do you mean by
there's a trace of elements before being replaced
? Do you mean that the items inside the range passed to notifyItemRangeChanged()
flicker, or something else?– Ben P.
Jan 2 at 22:55
@BenP. Yeah. In both the cases, the toPosition item is flickering.
– Sethuraman Srinivasan
Jan 2 at 23:04
@BenP. Yeah. In both the cases, the toPosition item is flickering.
– Sethuraman Srinivasan
Jan 2 at 23:04
add a comment |
1 Answer
1
active
oldest
votes
Try adding a third argument to your notifyItemRangeChanged()
calls. It can be literally any object, but I recommend Boolean.FALSE
since it won't take up any extra memory and because "false" and "don't run an animation I don't want" are sort of related concepts.
if (fromPosition < toPosition) {
notifyItemRangeChanged(fromPosition, list.size(), Boolean.FALSE);
} else {
notifyItemRangeChanged(toPosition, list.size(), Boolean.FALSE);
}
The reason this should work has to do with what the whole RecyclerView system does when you notify the adapter that items have changed. Part of that process involves the DefaultItemAnimator
, which has to decide whether to re-use old ViewHolder instances or not. You want this re-using, but you're not getting it.
When you pass a third argument to notifyItemRangeChanged()
, that third argument is passed around the system as a "payload". DefaultItemAnimator
is one piece of the system that receives this payload, and it decides whether or not to re-use ViewHolders based on whether or not this payload exists.
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
In your current code, there's no payload, so ViewHolders don't get re-used. This causes an animation of the "old" ViewHolder fading out and the "new" ViewHolder fading in, which looks an awful lot like a flicker.
When you add the third argument, suddenly there's a payload. Again, it doesn't matter what the payload is, just that it exists at all. Now your ViewHolder can be re-used, so there's no fade in/out animation.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54014199%2fdrag-and-drop-in-recyclerview-using-itemtouchviewer-without-affecting-the-animat%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Try adding a third argument to your notifyItemRangeChanged()
calls. It can be literally any object, but I recommend Boolean.FALSE
since it won't take up any extra memory and because "false" and "don't run an animation I don't want" are sort of related concepts.
if (fromPosition < toPosition) {
notifyItemRangeChanged(fromPosition, list.size(), Boolean.FALSE);
} else {
notifyItemRangeChanged(toPosition, list.size(), Boolean.FALSE);
}
The reason this should work has to do with what the whole RecyclerView system does when you notify the adapter that items have changed. Part of that process involves the DefaultItemAnimator
, which has to decide whether to re-use old ViewHolder instances or not. You want this re-using, but you're not getting it.
When you pass a third argument to notifyItemRangeChanged()
, that third argument is passed around the system as a "payload". DefaultItemAnimator
is one piece of the system that receives this payload, and it decides whether or not to re-use ViewHolders based on whether or not this payload exists.
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
In your current code, there's no payload, so ViewHolders don't get re-used. This causes an animation of the "old" ViewHolder fading out and the "new" ViewHolder fading in, which looks an awful lot like a flicker.
When you add the third argument, suddenly there's a payload. Again, it doesn't matter what the payload is, just that it exists at all. Now your ViewHolder can be re-used, so there's no fade in/out animation.
add a comment |
Try adding a third argument to your notifyItemRangeChanged()
calls. It can be literally any object, but I recommend Boolean.FALSE
since it won't take up any extra memory and because "false" and "don't run an animation I don't want" are sort of related concepts.
if (fromPosition < toPosition) {
notifyItemRangeChanged(fromPosition, list.size(), Boolean.FALSE);
} else {
notifyItemRangeChanged(toPosition, list.size(), Boolean.FALSE);
}
The reason this should work has to do with what the whole RecyclerView system does when you notify the adapter that items have changed. Part of that process involves the DefaultItemAnimator
, which has to decide whether to re-use old ViewHolder instances or not. You want this re-using, but you're not getting it.
When you pass a third argument to notifyItemRangeChanged()
, that third argument is passed around the system as a "payload". DefaultItemAnimator
is one piece of the system that receives this payload, and it decides whether or not to re-use ViewHolders based on whether or not this payload exists.
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
In your current code, there's no payload, so ViewHolders don't get re-used. This causes an animation of the "old" ViewHolder fading out and the "new" ViewHolder fading in, which looks an awful lot like a flicker.
When you add the third argument, suddenly there's a payload. Again, it doesn't matter what the payload is, just that it exists at all. Now your ViewHolder can be re-used, so there's no fade in/out animation.
add a comment |
Try adding a third argument to your notifyItemRangeChanged()
calls. It can be literally any object, but I recommend Boolean.FALSE
since it won't take up any extra memory and because "false" and "don't run an animation I don't want" are sort of related concepts.
if (fromPosition < toPosition) {
notifyItemRangeChanged(fromPosition, list.size(), Boolean.FALSE);
} else {
notifyItemRangeChanged(toPosition, list.size(), Boolean.FALSE);
}
The reason this should work has to do with what the whole RecyclerView system does when you notify the adapter that items have changed. Part of that process involves the DefaultItemAnimator
, which has to decide whether to re-use old ViewHolder instances or not. You want this re-using, but you're not getting it.
When you pass a third argument to notifyItemRangeChanged()
, that third argument is passed around the system as a "payload". DefaultItemAnimator
is one piece of the system that receives this payload, and it decides whether or not to re-use ViewHolders based on whether or not this payload exists.
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
In your current code, there's no payload, so ViewHolders don't get re-used. This causes an animation of the "old" ViewHolder fading out and the "new" ViewHolder fading in, which looks an awful lot like a flicker.
When you add the third argument, suddenly there's a payload. Again, it doesn't matter what the payload is, just that it exists at all. Now your ViewHolder can be re-used, so there's no fade in/out animation.
Try adding a third argument to your notifyItemRangeChanged()
calls. It can be literally any object, but I recommend Boolean.FALSE
since it won't take up any extra memory and because "false" and "don't run an animation I don't want" are sort of related concepts.
if (fromPosition < toPosition) {
notifyItemRangeChanged(fromPosition, list.size(), Boolean.FALSE);
} else {
notifyItemRangeChanged(toPosition, list.size(), Boolean.FALSE);
}
The reason this should work has to do with what the whole RecyclerView system does when you notify the adapter that items have changed. Part of that process involves the DefaultItemAnimator
, which has to decide whether to re-use old ViewHolder instances or not. You want this re-using, but you're not getting it.
When you pass a third argument to notifyItemRangeChanged()
, that third argument is passed around the system as a "payload". DefaultItemAnimator
is one piece of the system that receives this payload, and it decides whether or not to re-use ViewHolders based on whether or not this payload exists.
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
In your current code, there's no payload, so ViewHolders don't get re-used. This causes an animation of the "old" ViewHolder fading out and the "new" ViewHolder fading in, which looks an awful lot like a flicker.
When you add the third argument, suddenly there's a payload. Again, it doesn't matter what the payload is, just that it exists at all. Now your ViewHolder can be re-used, so there's no fade in/out animation.
answered Jan 2 at 23:29
Ben P.Ben P.
24.7k32250
24.7k32250
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54014199%2fdrag-and-drop-in-recyclerview-using-itemtouchviewer-without-affecting-the-animat%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
What do you mean by
there's a trace of elements before being replaced
? Do you mean that the items inside the range passed tonotifyItemRangeChanged()
flicker, or something else?– Ben P.
Jan 2 at 22:55
@BenP. Yeah. In both the cases, the toPosition item is flickering.
– Sethuraman Srinivasan
Jan 2 at 23:04