question

njsokalski avatar image
0 Votes"
njsokalski asked RobCaplan edited

Using ItemTouchHelper to Move an Item Multiple Spaces

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?

dotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

JarvanZhang-MSFT avatar image
0 Votes"
JarvanZhang-MSFT answered JarvanZhang-MSFT edited

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.


· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I think I found my problem. I was using NotifyDataSetChanged() instead of NotifyItemMoved(draggedindex, targetindex). Once I changed this it worked. Thanks for your help!

1 Vote 1 ·