6
votes

Is it possible to create a listview with draggable list items using Xamarin forms?

I have found a reference to this achieved in android in the link below but I'm not sure how I would go about this in Xamarin.Forms, I assume I will need to add platform specific code for this ?

How to make a ListView with draggable items?

Additionally as seen by the below Xamarin forum post it seems that controls dont support drag/drop functionality therefore a custom renderer would need to be created but im not quite sure where to begin

http://forums.xamarin.com/discussion/18114/do-the-xamarin-forms-controls-support-drag-drop-runtime-functionality

2
If anybody looking for xamarin android native solution for draggable list then you can check out here : appliedcodelog.com/2019/08/…Suchith

2 Answers

3
votes

For iOS, you can take advantage of the native UITableView control's reordering functionality. Create a custom renderer for a ListView that tells iOS that you'd like all rows to be movable. Have it update the source list's order to match the user's actions.

Start with a subclass.

public class EditListView : ListView { }

Then add a custom renderer that updates ListView.ItemsSource to reflect the changed order. This code assumes ItemsSource is a List<ListItem>, where ListItem has Id and Name properties of type string.

[assembly: ExportRenderer(typeof(EditListView), typeof(EditListViewRenderer))]
public class EditListViewRenderer : ListViewRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
    {
        base.OnElementChanged(e);

        if (e.NewElement != null) {
            Control.Source = new TableViewSource((List<ListItem>)e.NewElement.ItemsSource);
            Control.Editing = true;
        }
    }

    class TableViewSource : UITableViewSource
    {
        readonly List<ListItem> items;

        public TableViewSource(List<ListItem> items) { this.items = items; }

        public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            var item = items[indexPath.Row];
            var cell = new UITableViewCell(UITableViewCellStyle.Default, item.Id); // No recycling. If the list is big enough to need recycling, the user won't be very happy about reordering it by hand. :-)
            cell.TextLabel.Text = item.Name;
            return cell;
        }

        public override void MoveRow(UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
        {
            int source = sourceIndexPath.Row, dest = destinationIndexPath.Row;
            var movedItem = items[source];
            items.RemoveAt(source);
            if (source > dest) --source;
            items.Insert(dest, movedItem);
        }

        public override nint RowsInSection(UITableView tableview, nint section) => items.Count;
        public override bool CanMoveRow(UITableView tableView, NSIndexPath indexPath) => true;
        public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath) => true; // Only editable rows can be moved.
        public override bool ShouldIndentWhileEditing(UITableView tableView, NSIndexPath indexPath) => false;
        public override UITableViewCellEditingStyle EditingStyleForRow(UITableView tableView, NSIndexPath indexPath) => UITableViewCellEditingStyle.None;
    }
}
2
votes

As pointed out on your link, its not possible just using the supplied Xamarin.Forms controls.

You would therefore have to implement Custom Renderers, for each platform.

A great tutorial can be found on http://developer.xamarin.com/guides/cross-platform/xamarin-forms/custom-renderer/

At the very bottom of that page is a video that I really advise you to go through as it is very informative and should get you into writing your own Custom Renderer classes for Android and iOS. The same principles apply to Windows Phone so if you wanted to target that also it shouldn't be too difficult also.