private void EnableDragAndDrop(bool isEnabled, DragAndDropTrigger dragAndDropTrigger) { if (_dragAndDropGesture != null) { Control.RemoveGestureRecognizer(_dragAndDropGesture); _dragAndDropGesture = null; return; } if (!isEnabled) { return; } int from = -1; NSIndexPath pathTo = null; iOSViewCell draggedViewCell = null; // Create a custom gesture recognizer _dragAndDropGesture = dragAndDropTrigger == DragAndDropTrigger.Pan ? new UIPanGestureRecognizer( gesture => { // Take action based on state HandleDragByGestureState(gesture.State, gesture, ref from, ref pathTo, ref draggedViewCell); }) : new UILongPressGestureRecognizer( gesture => { // Take action based on state HandleDragByGestureState(gesture.State, gesture, ref from, ref pathTo, ref draggedViewCell); }); // Add the custom recognizer to the collection view Control.AddGestureRecognizer(_dragAndDropGesture); }
private void HandleDragByGestureState( UIGestureRecognizerState state, UIGestureRecognizer gesture, ref int from, ref NSIndexPath pathTo, ref iOSViewCell draggedViewCell) { switch (state) { case UIGestureRecognizerState.Began: var selectedIndexPath = Control.IndexPathForItemAtPoint(gesture.LocationInView(Control)); if (selectedIndexPath != null) { draggedViewCell = (iOSViewCell)Control.CellForItem(selectedIndexPath); if (draggedViewCell.FormsCell is DraggableViewCell draggableViewCell) { if (!draggableViewCell.IsDraggable) { Control.CancelInteractiveMovement(); return; } draggableViewCell.IsDragAndDropping = true; } from = (int)selectedIndexPath.Item; Control.BeginInteractiveMovementForItem(selectedIndexPath); Element.IsDragAndDropping = true; Element.DragAndDropStartedCommand?.Execute( new DragAndDropInfo(from, -1, Element.BindingContext)); } break; case UIGestureRecognizerState.Changed: if (draggedViewCell == null) { return; } var gestureLocation = gesture.LocationInView(gesture.View); var changedPath = Control.IndexPathForItemAtPoint(gestureLocation); if (changedPath != null) { draggedViewCell = (iOSViewCell)Control.CellForItem(changedPath); if (draggedViewCell == null || (draggedViewCell.FormsCell is DraggableViewCell draggableViewCell && !draggableViewCell.IsDraggable)) { pathTo = null; // System.Diagnostics.Debug.WriteLine("Cancel change state"); return; } pathTo = changedPath; // System.Diagnostics.Debug.WriteLine($"State changed to {pathTo.Item}"); } switch (Element.DragAndDropDirection) { case DragAndDropDirection.HorizontalOnly: Control.UpdateInteractiveMovement(new CGPoint(gestureLocation.X, draggedViewCell.Center.Y)); break; case DragAndDropDirection.VerticalOnly: Control.UpdateInteractiveMovement(new CGPoint(draggedViewCell.Center.X, gestureLocation.Y)); break; default: Control.UpdateInteractiveMovement(gestureLocation); break; } break; case UIGestureRecognizerState.Ended: if (from < 0 || pathTo == null) { // System.Diagnostics.Debug.WriteLine($"Ended but cancelled cause incorrect parameters"); Control.CancelInteractiveMovement(); return; } var targetViewCell = (iOSViewCell)Control.CellForItem(pathTo); if (targetViewCell?.FormsCell is DraggableViewCell targetDraggableViewCell && !targetDraggableViewCell.IsDraggable) { // System.Diagnostics.Debug.WriteLine($"Ended but cancelled cause target is not draggable"); Control.CancelInteractiveMovement(); return; } // System.Diagnostics.Debug.WriteLine($"Ended from: {from} to: {pathTo.Item}"); Control.EndInteractiveMovement(); if (_itemsSource is IList itemsSourceList) { try { _isMovedBackfire = true; var item = itemsSourceList[from]; itemsSourceList.RemoveAt(from); itemsSourceList.Insert((int)pathTo.Item, item); var to = itemsSourceList.IndexOf(item); Element.IsDragAndDropping = false; if (draggedViewCell?.FormsCell is DraggableViewCell draggableViewCell) { draggableViewCell.IsDragAndDropping = false; Element.DragAndDropEndedCommand?.Execute( new DragAndDropInfo(from, to, draggableViewCell.BindingContext)); } draggedViewCell = null; } finally { _isMovedBackfire = false; } } break; default: Control.CancelInteractiveMovement(); break; } }