6using System.Collections.Generic;
12 [RequireComponent(typeof(RectTransform), typeof(LayoutElement))]
15 [Tooltip(
"Can this element be dragged?")]
17 [Tooltip(
"Can this element be transfered to another list")]
19 [Tooltip(
"Can this element be dropped in space?")]
23 private readonly List<RaycastResult> _raycastResults =
new List<RaycastResult>();
26 private int _fromIndex;
27 private RectTransform _draggingObject;
28 private LayoutElement _draggingObjectLE;
29 private Vector2 _draggingObjectOriginalSize;
31 private RectTransform _fakeElement;
32 private LayoutElement _fakeElementLE;
34 private int _displacedFromIndex;
35 private RectTransform _displacedObject;
36 private LayoutElement _displacedObjectLE;
37 private Vector2 _displacedObjectOriginalSize;
40 private bool _isDragging;
41 private RectTransform _rect;
43 private CanvasGroup _canvasGroup;
44 internal bool isValid;
47 #region IBeginDragHandler Members
51 _canvasGroup.blocksRaycasts =
false;
53 if (_reorderableList ==
null)
57 if (!_reorderableList.
IsDraggable || !
this.IsGrabbable)
59 _draggingObject =
null;
66 _draggingObject = _rect;
67 _fromIndex = _rect.GetSiblingIndex();
68 _displacedFromIndex = -1;
74 DroppedObject = _draggingObject.gameObject,
75 IsAClone = _reorderableList.CloneDraggedObject,
76 SourceObject = _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject,
77 FromList = _reorderableList,
78 FromIndex = _fromIndex,
83 _draggingObject =
null;
90 GameObject clone = (GameObject)Instantiate(gameObject);
91 _draggingObject = clone.GetComponent<RectTransform>();
95 _draggingObjectOriginalSize = gameObject.GetComponent<RectTransform>().rect.size;
96 _draggingObjectLE = _draggingObject.GetComponent<LayoutElement>();
97 _draggingObject.SetParent(_reorderableList.
DraggableArea,
true);
98 _draggingObject.SetAsLastSibling();
102 _fakeElement =
new GameObject(
"Fake").AddComponent<RectTransform>();
103 _fakeElementLE = _fakeElement.gameObject.AddComponent<LayoutElement>();
112 DroppedObject = _draggingObject.gameObject,
113 IsAClone = _reorderableList.CloneDraggedObject,
114 SourceObject = _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject,
115 FromList = _reorderableList,
116 FromIndex = _fromIndex,
132 #region IDragHandler Members
134 public void OnDrag(PointerEventData eventData)
144 var canvas = _draggingObject.GetComponentInParent<Canvas>();
146 RectTransformUtility.ScreenPointToWorldPointInRectangle(canvas.GetComponent<RectTransform>(), eventData.position,
147 canvas.renderMode != RenderMode.ScreenSpaceOverlay ? canvas.worldCamera :
null, out worldPoint);
148 _draggingObject.position = worldPoint;
150 ReorderableList _oldReorderableListRaycasted = _currentReorderableListRaycasted;
153 EventSystem.current.RaycastAll(eventData, _raycastResults);
154 for (
int i = 0; i < _raycastResults.Count; i++)
156 _currentReorderableListRaycasted = _raycastResults[i].gameObject.GetComponent<
ReorderableList>();
157 if (_currentReorderableListRaycasted !=
null)
164 if (_currentReorderableListRaycasted ==
null || _currentReorderableListRaycasted.
IsDropable ==
false
165 || (_oldReorderableListRaycasted != _reorderableList && !
IsTransferable)
166 || ((_fakeElement.parent == _currentReorderableListRaycasted.
Content
167 ? _currentReorderableListRaycasted.
Content.childCount - 1
168 : _currentReorderableListRaycasted.
Content.childCount) >= _currentReorderableListRaycasted.
maxItems && !_currentReorderableListRaycasted.
IsDisplacable)
169 || _currentReorderableListRaycasted.
maxItems <= 0)
172 _fakeElement.transform.SetParent(_reorderableList.
DraggableArea,
false);
174 if (_displacedObject !=
null)
176 revertDisplacedElement();
182 if (_currentReorderableListRaycasted.
Content.childCount < _currentReorderableListRaycasted.
maxItems && _fakeElement.parent != _currentReorderableListRaycasted.
Content)
184 _fakeElement.SetParent(_currentReorderableListRaycasted.
Content,
false);
187 float minDistance =
float.PositiveInfinity;
190 for (
int j = 0; j < _currentReorderableListRaycasted.
Content.childCount; j++)
192 var c = _currentReorderableListRaycasted.
Content.GetChild(j).GetComponent<RectTransform>();
194 if (_currentReorderableListRaycasted.
ContentLayout is VerticalLayoutGroup)
195 dist = Mathf.Abs(c.position.y - worldPoint.y);
196 else if (_currentReorderableListRaycasted.
ContentLayout is HorizontalLayoutGroup)
197 dist = Mathf.Abs(c.position.x - worldPoint.x);
198 else if (_currentReorderableListRaycasted.
ContentLayout is GridLayoutGroup)
199 dist = (Mathf.Abs(c.position.x - worldPoint.x) + Mathf.Abs(c.position.y - worldPoint.y));
201 if (dist < minDistance)
207 if ((_currentReorderableListRaycasted != _oldReorderableListRaycasted || targetIndex != _displacedFromIndex)
208 && _currentReorderableListRaycasted.
Content.childCount == _currentReorderableListRaycasted.
maxItems)
210 Transform toDisplace = _currentReorderableListRaycasted.
Content.GetChild(targetIndex);
211 if (_displacedObject !=
null)
213 revertDisplacedElement();
214 if (_currentReorderableListRaycasted.
Content.childCount > _currentReorderableListRaycasted.
maxItems)
216 displaceElement(targetIndex, toDisplace);
219 else if (_fakeElement.parent != _currentReorderableListRaycasted.
Content)
221 _fakeElement.SetParent(_currentReorderableListRaycasted.
Content,
false);
222 displaceElement(targetIndex, toDisplace);
226 _fakeElement.SetSiblingIndex(targetIndex);
227 _fakeElement.gameObject.SetActive(
true);
237 private void displaceElement(
int targetIndex, Transform displaced)
239 _displacedFromIndex = targetIndex;
240 _displacedObjectOriginList = _currentReorderableListRaycasted;
241 _displacedObject = displaced.GetComponent<RectTransform>();
242 _displacedObjectLE = _displacedObject.GetComponent<LayoutElement>();
243 _displacedObjectOriginalSize = _displacedObject.rect.size;
247 DroppedObject = _displacedObject.gameObject,
248 FromList = _currentReorderableListRaycasted,
249 FromIndex = targetIndex,
253 int c = _fakeElement.parent == _reorderableList.
Content
254 ? _reorderableList.
Content.childCount - 1
255 : _reorderableList.
Content.childCount;
257 if (_reorderableList.
IsDropable && c < _reorderableList.
maxItems && _displacedObject.GetComponent<ReorderableListElement>().IsTransferable)
259 _displacedObjectLE.preferredWidth = _draggingObjectOriginalSize.x;
260 _displacedObjectLE.preferredHeight = _draggingObjectOriginalSize.y;
261 _displacedObject.SetParent(_reorderableList.
Content,
false);
262 _displacedObject.rotation = _reorderableList.transform.rotation;
263 _displacedObject.SetSiblingIndex(_fromIndex);
266 _currentReorderableListRaycasted.
Refresh();
268 args.ToList = _reorderableList;
269 args.ToIndex = _fromIndex;
273 else if (_displacedObject.GetComponent<ReorderableListElement>().isDroppableInSpace)
275 _displacedObject.SetParent(_currentReorderableListRaycasted.
DraggableArea,
true);
276 _currentReorderableListRaycasted.
Refresh();
277 _displacedObject.position +=
new Vector3(_draggingObjectOriginalSize.x / 2, _draggingObjectOriginalSize.y / 2, 0);
281 _displacedObject.SetParent(
null,
true);
282 _displacedObjectOriginList.
Refresh();
283 _displacedObject.gameObject.SetActive(
false);
289 private void revertDisplacedElement()
291 var args =
new ReorderableList.ReorderableListEventStruct
293 DroppedObject = _displacedObject.gameObject,
294 FromList = _displacedObjectOriginList,
295 FromIndex = _displacedFromIndex,
297 if (_displacedObject.parent !=
null)
299 args.ToList = _reorderableList;
300 args.ToIndex = _fromIndex;
303 _displacedObjectLE.preferredWidth = _displacedObjectOriginalSize.x;
304 _displacedObjectLE.preferredHeight = _displacedObjectOriginalSize.y;
305 _displacedObject.SetParent(_displacedObjectOriginList.
Content,
false);
306 _displacedObject.rotation = _displacedObjectOriginList.transform.rotation;
307 _displacedObject.SetSiblingIndex(_displacedFromIndex);
308 _displacedObject.gameObject.SetActive(
true);
312 _displacedObjectOriginList.
Refresh();
314 if (args.ToList !=
null)
322 _displacedFromIndex = -1;
323 _displacedObjectOriginList =
null;
324 _displacedObject =
null;
325 _displacedObjectLE =
null;
332 if (_displacedObject.parent ==
null)
334 Destroy(_displacedObject.gameObject);
336 _displacedFromIndex = -1;
337 _displacedObjectOriginList =
null;
338 _displacedObject =
null;
339 _displacedObjectLE =
null;
345 #region IEndDragHandler Members
351 if (_draggingObject !=
null)
355 if (_currentReorderableListRaycasted !=
null && _fakeElement.parent == _currentReorderableListRaycasted.
Content)
359 DroppedObject = _draggingObject.gameObject,
361 SourceObject = _reorderableList.
CloneDraggedObject ? gameObject : _draggingObject.gameObject,
362 FromList = _reorderableList,
363 FromIndex = _fromIndex,
364 ToList = _currentReorderableListRaycasted,
365 ToIndex = _fakeElement.GetSiblingIndex()
378 _draggingObject.SetParent(_currentReorderableListRaycasted.
Content,
false);
379 _draggingObject.rotation = _currentReorderableListRaycasted.transform.rotation;
380 _draggingObject.SetSiblingIndex(_fakeElement.GetSiblingIndex());
383 _currentReorderableListRaycasted.
Refresh();
388 if (_displacedObject !=
null)
394 throw new Exception(
"It's too late to cancel the Transfer! Do so in OnElementDropped!");
400 if (this.isDroppableInSpace)
404 DroppedObject = _draggingObject.gameObject,
405 IsAClone = _reorderableList.CloneDraggedObject,
407 _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject,
408 FromList = _reorderableList,
409 FromIndex = _fromIndex
418 if (_currentReorderableListRaycasted !=
null)
420 if ((_currentReorderableListRaycasted.
Content.childCount >=
421 _currentReorderableListRaycasted.
maxItems &&
423 || _currentReorderableListRaycasted.
maxItems <= 0)
425 GameObject o = _draggingObject.gameObject;
430 IsAClone = _reorderableList.CloneDraggedObject,
431 SourceObject = _reorderableList.CloneDraggedObject ? gameObject : o,
432 FromList = _reorderableList,
433 ToList = _currentReorderableListRaycasted,
434 FromIndex = _fromIndex
443 if (_fakeElement !=
null)
445 Destroy(_fakeElement.gameObject);
448 _canvasGroup.blocksRaycasts =
true;
460 Destroy(_draggingObject.gameObject);
466 _draggingObject.SetParent(_reorderableList.
Content,
false);
467 _draggingObject.rotation = _reorderableList.
Content.transform.rotation;
468 _draggingObject.SetSiblingIndex(_fromIndex);
471 var args =
new ReorderableList.ReorderableListEventStruct
473 DroppedObject = _draggingObject.gameObject,
475 SourceObject = _reorderableList.
CloneDraggedObject ? gameObject : _draggingObject.gameObject,
476 FromList = _reorderableList,
477 FromIndex = _fromIndex,
478 ToList = _reorderableList,
487 throw new Exception(
"Transfer is already Canceled.");
492 if (_fakeElement !=
null)
494 Destroy(_fakeElement.gameObject);
497 if (_displacedObject !=
null)
499 revertDisplacedElement();
501 _canvasGroup.blocksRaycasts =
true;
504 private void RefreshSizes()
506 Vector2 size = _draggingObjectOriginalSize;
508 if (_currentReorderableListRaycasted !=
null
509 && _currentReorderableListRaycasted.
IsDropable
510 && _currentReorderableListRaycasted.
Content.childCount > 0
513 var firstChild = _currentReorderableListRaycasted.
Content.GetChild(0);
514 if (firstChild !=
null)
516 size = firstChild.GetComponent<RectTransform>().rect.size;
520 _draggingObject.sizeDelta = size;
521 _fakeElementLE.preferredHeight = _draggingObjectLE.preferredHeight = size.y;
522 _fakeElementLE.preferredWidth = _draggingObjectLE.preferredWidth = size.x;
523 _fakeElement.GetComponent<RectTransform>().sizeDelta = size;
528 _reorderableList = reorderableList;
529 _rect = GetComponent<RectTransform>();
530 _canvasGroup = gameObject.GetOrAddComponent<CanvasGroup>();
void OnEndDrag(PointerEventData eventData)
void OnBeginDrag(PointerEventData eventData)
void OnDrag(PointerEventData eventData)
void finishDisplacingElement()
void Init(ReorderableList reorderableList)
ReorderableListHandler OnElementRemoved
ReorderableListHandler OnElementAdded
void Refresh()
Refresh related list content
ReorderableListHandler OnElementDisplacedFromReturned
ReorderableListHandler OnElementDisplacedFrom
ReorderableListHandler OnElementDropped
ReorderableListHandler OnElementDisplacedTo
ReorderableListHandler OnElementGrabbed
ReorderableListHandler OnElementDisplacedToReturned
LayoutGroup ContentLayout
RectTransform DraggableArea
ReorderableListHandler OnElementDroppedWithMaxItems
Credit Erdener Gonenc - @PixelEnvision.