-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
DragAndDropExtensions.cs
114 lines (99 loc) · 5.24 KB
/
DragAndDropExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
using System;
using System.Linq;
using DeveloperSample.Core.Helpers;
using DeveloperSample.Core.Pages.DragAndDrop.Sample3.Interfaces;
using Xamarin.Forms;
namespace DeveloperSample.Core.Pages.DragAndDrop.Sample3.Extensions
{
public static class DragAndDropExtensions
{
#region IDragAndDropMovingView
private static VisualElement GetContainer(this IDragAndDropMovingView view)
{
if (!(view is VisualElement visualElement))
throw new Exception($"{nameof(IDragAndDropMovingView)} can only be an interface on a {nameof(View)}");
var dropContainer = visualElement.GetFirstParentOfType<IDragAndDropContainer>();
if (dropContainer is VisualElement output) return output;
return visualElement.GetFirstParentOfType<Page>();
}
public static void InitializeDragAndDrop(this IDragAndDropMovingView view)
{
if (!(view is View output))
throw new Exception($"{nameof(IDragAndDropMovingView)} can only be an interface on a {nameof(View)}");
var panGestureRecognizer = new PanGestureRecognizer
{
TouchPoints = 1
};
panGestureRecognizer.PanUpdated += PanGestureRecognizer_PanUpdated;
output.GestureRecognizers.Clear();
output.GestureRecognizers.Add(panGestureRecognizer);
}
private static void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e)
{
if (!(sender is VisualElement visualElement) ||
!(sender is IDragAndDropMovingView dragAndDropMovingView))
throw new Exception($"{nameof(IDragAndDropMovingView)} can only be an interface on a {nameof(View)}");
var dropContainer = dragAndDropMovingView.GetContainer();
// Update on Drop
if (e.StatusType == GestureStatus.Completed)
dropContainer?.DragAndDroppableViewDropped(dragAndDropMovingView);
// Coordinate of center = Initial position of top left corner + Pan transformation + Size / 2
var screenCoordinates = visualElement.GetScreenCoordinates();
switch (e.StatusType)
{
case GestureStatus.Running:
visualElement.TranslationX = (Device.RuntimePlatform == Device.Android ? visualElement.TranslationX : 0) + e.TotalX;
visualElement.TranslationY = (Device.RuntimePlatform == Device.Android ? visualElement.TranslationY : 0) + e.TotalY;
dragAndDropMovingView.ScreenX = screenCoordinates.X + (Device.RuntimePlatform == Device.Android ? visualElement.TranslationX : 0) + e.TotalX + visualElement.Width / 2;
dragAndDropMovingView.ScreenY = screenCoordinates.Y + (Device.RuntimePlatform == Device.Android ? visualElement.TranslationY : 0) + e.TotalY + visualElement.Height / 2;
break;
case GestureStatus.Completed:
case GestureStatus.Canceled:
visualElement.TranslateTo(0, 0, 200);
dragAndDropMovingView.ScreenX = screenCoordinates.X + visualElement.Width / 2;
dragAndDropMovingView.ScreenY = screenCoordinates.Y + visualElement.Height / 2;
break;
}
// Update on Hover
dropContainer?.UpdateHoverStatuses();
}
#endregion
#region IDragAndDropContainer
private static void UpdateHoverStatuses(this VisualElement view)
{
var allReceivers = view.GetAllChildrenOfType<IDragAndDropHoverableView>();
var allSenders = view.GetAllChildrenOfType<IDragAndDropMovingView>();
foreach (var receiver in allReceivers)
{
if (!(receiver is VisualElement veReceiver)) continue;
var x = veReceiver.GetScreenCoordinates().X;
var y = veReceiver.GetScreenCoordinates().Y;
var width = veReceiver.Width;
var height = veReceiver.Height;
receiver.OnHovered(allSenders.Where(sender => sender.ScreenX >= x &&
sender.ScreenX <= x + width &&
sender.ScreenY >= y &&
sender.ScreenY <= y + height
).ToList());
}
}
private static void DragAndDroppableViewDropped(this VisualElement view, IDragAndDropMovingView sender)
{
var allReceivers = view.GetAllChildrenOfType<IDragAndDropReceivingView>();
foreach (var receiver in allReceivers)
{
if (!(receiver is VisualElement veReceiver)) continue;
var x = veReceiver.GetScreenCoordinates().X;
var y = veReceiver.GetScreenCoordinates().Y;
var width = veReceiver.Width;
var height = veReceiver.Height;
if (sender.ScreenX >= x &&
sender.ScreenX <= x + width &&
sender.ScreenY >= y &&
sender.ScreenY <= y + height)
receiver.OnDropReceived(sender);
}
}
#endregion
}
}