Drag and drop in Recyclerview using itemTouchViewer without affecting the animation












1















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.










share|improve this question























  • 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
















1















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.










share|improve this question























  • 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














1












1








1








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.










share|improve this question














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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 2 at 22:50









Sethuraman SrinivasanSethuraman Srinivasan

333618




333618













  • 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



















  • 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

















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












1 Answer
1






active

oldest

votes


















1














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.






share|improve this answer























    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    1














    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.






    share|improve this answer




























      1














      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.






      share|improve this answer


























        1












        1








        1







        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.






        share|improve this answer













        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jan 2 at 23:29









        Ben P.Ben P.

        24.7k32250




        24.7k32250
































            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Monofisismo

            Angular Downloading a file using contenturl with Basic Authentication

            Olmecas