Using ItemTouchHelper to Move an Item Multiple Spaces

Nathan Sokalski 4,116 Reputation points
2021-04-13T23:26:58.25+00:00

I have created a RecyclerView, RecyclerView.Callback, and RecyclerView.ItemTouchHelper that allows the user to reorder the items by dragging. This is mostly successful, except for the fact that it only allows me to drag the item 1 space at a time, even if I do not lift my finger. How can I fix this?

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,294 questions
0 comments No comments
{count} votes

Accepted answer
  1. JarvanZhang 23,936 Reputation points
    2021-04-14T03:19:59.117+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    except for the fact that it only allows me to drag the item 1 space at a time, even if I do not lift my finger.

    Hi, how did you create the touch-drag function for the recyclerView? I created a basic demo to test the function, it works as expeted on my side. Here is the sample code:

    MainActivity class

       public class MainActivity : AppCompatActivity, IOnStartDragListener  
       {  
           public static MainActivity Instance;  
           RecyclerView recyclerView;  
           RecyclerView.LayoutManager layoutManager;  
           public static ObservableCollection<TestModel> data;  
           private ItemTouchHelper _mItemTouchHelper;  
         
           protected override void OnCreate(Bundle savedInstanceState)  
           {  
               base.OnCreate(savedInstanceState);  
               Xamarin.Essentials.Platform.Init(this, savedInstanceState);  
               SetContentView(Resource.Layout.activity_main);  
         
               Instance = this;  
         
               recyclerView = FindViewById<RecyclerView>(Resource.Id.test_recyclerView);  
               layoutManager = new LinearLayoutManager(this);  
         
               data = new ObservableCollection<TestModel>();  
               data.Add(new TestModel { content = "item_1" });  
               data.Add(new TestModel { content = "item_2" });  
               data.Add(new TestModel { content = "item_3" });  
         
               TestAdapter testAdapter = new TestAdapter(data, this);  
               recyclerView.SetLayoutManager(layoutManager);  
               recyclerView.SetAdapter(testAdapter);  
         
               ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(testAdapter);  
               _mItemTouchHelper = new ItemTouchHelper(callback);  
               _mItemTouchHelper.AttachToRecyclerView(recyclerView);  
           }  
         
           public void OnStartDrag(RecyclerView.ViewHolder viewHolder)  
           {  
               _mItemTouchHelper.StartDrag(viewHolder);  
           }  
       }  
    

    ViewHolder and Adapter class

       public class TestViewHolder : RecyclerView.ViewHolder  
       {  
           public TextView ItemText { get; set; }  
           public TestViewHolder(View itemView) : base(itemView)  
           {  
               ItemText = itemView.FindViewById<TextView>(Resource.Id.itemText);  
           }  
       }  
         
       public class TestAdapter : RecyclerView.Adapter, ITemTouchHelperAdapter, IOnLongClickListener  
       {  
           public ObservableCollection<TestModel> list;  
           TestViewHolder viewHolder;  
           private readonly IOnStartDragListener dragStartListener;  
         
           public TestAdapter(ObservableCollection<TestModel> list, IOnStartDragListener dragStartListener)  
           {  
               this.list = list;  
               this.dragStartListener = dragStartListener;  
           }  
           public override int ItemCount  
           {  
               get  
               {  
                   return list.Count;  
               }  
           }  
           public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)  
           {  
               viewHolder = holder as TestViewHolder;  
               viewHolder.ItemText.Text = list[position].content;  
           }  
           public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)  
           {  
               View itemView = LayoutInflater.From(MainActivity.Instance).Inflate(Resource.Layout.recyclerView_itemLayout, parent, false);  
               TestViewHolder viewHolder = new TestViewHolder(itemView);  
               return viewHolder;  
           }  
           public bool OnItemMove(int fromPosition, int toPosition)  
           {  
               var tempPlanResource = list[fromPosition];  
               list[fromPosition] = list[toPosition];  
               list[toPosition] = tempPlanResource;  
               MainActivity.data = list;  
               NotifyItemMoved(fromPosition, toPosition);  
               return true;  
           }  
           public void OnItemDismiss(int position)  
           {  
               var item = list[position];  
               list.Remove(item);  
               NotifyItemRemoved(position);  
           }  
           public bool OnLongClick(View v)  
           {  
               dragStartListener.OnStartDrag(viewHolder);  
               return true;  
           }  
       }  
         
       public class TestModel  
       {  
           public string content { get; set; }  
       }  
    

    Related interfaces and touch callback class

       public interface IOnStartDragListener  
       {  
           void OnStartDrag(RecyclerView.ViewHolder viewHolder);  
       }  
         
       public interface ITemTouchHelperAdapter  
       {  
           bool OnItemMove(int fromPosition, int toPosition);  
           void OnItemDismiss(int position);  
       }  
         
       public class SimpleItemTouchHelperCallback : ItemTouchHelper.Callback  
       {  
           private readonly ITemTouchHelperAdapter _mAdapter;  
           public SimpleItemTouchHelperCallback(ITemTouchHelperAdapter adapter)  
           {  
               _mAdapter = adapter;  
           }  
           public override int GetMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)  
           {  
               const int dragFlags = ItemTouchHelper.Up | ItemTouchHelper.Down;  
               const int swipeFlags = ItemTouchHelper.ActionStateIdle;  
               return MakeMovementFlags(dragFlags, swipeFlags);  
           }  
           public override bool OnMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)  
           {  
               if (viewHolder.ItemViewType != target.ItemViewType)  
               {  
                   return false;  
               }  
               _mAdapter.OnItemMove(viewHolder.AdapterPosition, target.AdapterPosition);  
               return true;  
           }  
           public override void OnSwiped(RecyclerView.ViewHolder viewHolder, int direction)  
           {  
               _mAdapter.OnItemDismiss(viewHolder.AdapterPosition);  
           }  
       }  
    

    I found this solution by searching on the keywords ReOrder the list items by drag and drop in xamarin android using RecyclerView to check the related documentation.

    Best Regards,

    Jarvan Zhang


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful