add ReorderableList
only vertical for now... --HG-- branch : Ziboo-ReorderableListrelease
parent
e346eef69d
commit
36aa65f226
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
public class ReorderableList : MonoBehaviour
|
||||
{
|
||||
public RectTransform Content;
|
||||
|
||||
public bool IsDraggable = true;
|
||||
public RectTransform DraggableArea;
|
||||
public bool CloneDraggedObject = false;
|
||||
|
||||
public bool IsDropable = true;
|
||||
|
||||
|
||||
public ReorderableListHandler OnElementDropped = new ReorderableListHandler();
|
||||
|
||||
private ReorderableListContent _listContent;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Content == null)
|
||||
{
|
||||
Debug.LogError("You need to set the content for the list", gameObject);
|
||||
return;
|
||||
}
|
||||
if (DraggableArea == null)
|
||||
{
|
||||
Debug.LogError("You need to set a draggable area for the list", gameObject);
|
||||
return;
|
||||
}
|
||||
_listContent = Content.gameObject.AddComponent<ReorderableListContent>();
|
||||
_listContent.Init(this);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct ReorderableListEventStruct
|
||||
{
|
||||
public GameObject DropedObject;
|
||||
public int FromIndex;
|
||||
public ReorderableList FromList;
|
||||
public bool IsAClone;
|
||||
public GameObject SourceObject;
|
||||
public int ToIndex;
|
||||
public ReorderableList ToList;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ReorderableListHandler : UnityEvent<ReorderableListEventStruct>
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b333d67eb08d464d823874f6a1666c2
|
||||
timeCreated: 1446072130
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9b8d590979bc3264ab9a7df11a0e8c3c
|
||||
timeCreated: 1446061891
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,58 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ReorderableListContent : MonoBehaviour
|
||||
{
|
||||
private List<Transform> _cachedChildren;
|
||||
private List<ReorderableListElement> _cachedListElement;
|
||||
private ReorderableListElement _ele;
|
||||
private ReorderableList _extList;
|
||||
private RectTransform _rect;
|
||||
|
||||
public void OnTransformChildrenChanged()
|
||||
{
|
||||
StartCoroutine(RefreshChildren());
|
||||
}
|
||||
|
||||
public void Init(ReorderableList extList)
|
||||
{
|
||||
_extList = extList;
|
||||
_rect = GetComponent<RectTransform>();
|
||||
_cachedChildren = new List<Transform>();
|
||||
_cachedListElement = new List<ReorderableListElement>();
|
||||
|
||||
StartCoroutine(RefreshChildren());
|
||||
}
|
||||
|
||||
private IEnumerator RefreshChildren()
|
||||
{
|
||||
//Handle new chilren
|
||||
for (int i = 0; i < _rect.childCount; i++)
|
||||
{
|
||||
if (_cachedChildren.Contains(_rect.GetChild(i)))
|
||||
continue;
|
||||
|
||||
//Get or Create ReorderableListElement
|
||||
_ele = _rect.GetChild(i).gameObject.GetComponent<ReorderableListElement>() ??
|
||||
_rect.GetChild(i).gameObject.AddComponent<ReorderableListElement>();
|
||||
_ele.Init(_extList);
|
||||
|
||||
_cachedChildren.Add(_rect.GetChild(i));
|
||||
_cachedListElement.Add(_ele);
|
||||
}
|
||||
|
||||
//HACK a little hack, if I don't wait one frame I don't have the right deleted children
|
||||
yield return 0;
|
||||
|
||||
//Remove deleted child
|
||||
for (int i = _cachedChildren.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (_cachedChildren[i] == null)
|
||||
{
|
||||
_cachedChildren.RemoveAt(i);
|
||||
_cachedListElement.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 252dd148b2c1dbe40b7d938a553e3caf
|
||||
timeCreated: 1446062045
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class ReorderableListDebug : MonoBehaviour
|
||||
{
|
||||
|
||||
public Text DebugLabel;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
foreach (var list in FindObjectsOfType<ReorderableList>())
|
||||
{
|
||||
list.OnElementDropped.AddListener(ElementDropped);
|
||||
}
|
||||
}
|
||||
|
||||
private void ElementDropped(ReorderableList.ReorderableListEventStruct droppedStruct)
|
||||
{
|
||||
DebugLabel.text = "";
|
||||
DebugLabel.text += "Dropped Object: " + droppedStruct.DropedObject.name + "\n";
|
||||
DebugLabel.text += "Is Clone ?: " + droppedStruct.IsAClone + "\n";
|
||||
if (droppedStruct.IsAClone)
|
||||
DebugLabel.text += "Source Object: " + droppedStruct.SourceObject.name + "\n";
|
||||
DebugLabel.text += string.Format("From {0} at Index {1} \n", droppedStruct.FromList.name,droppedStruct.FromIndex);
|
||||
DebugLabel.text += string.Format("To {0} at Index {1} \n", droppedStruct.ToList.name,droppedStruct.ToIndex);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 86c224aef3e999140b78d1d7135ba33f
|
||||
timeCreated: 1446072313
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,159 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
[RequireComponent(typeof (RectTransform))]
|
||||
public class ReorderableListElement : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
|
||||
{
|
||||
private readonly List<RaycastResult> _raycastResults = new List<RaycastResult>();
|
||||
private ReorderableList _currentReorderableListRaycasted;
|
||||
private RectTransform _draggingObject;
|
||||
private ReorderableList _reorderableList;
|
||||
private RectTransform _fakeElement;
|
||||
private int _fromIndex;
|
||||
private bool _isDragging;
|
||||
private RectTransform _rect;
|
||||
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (_reorderableList == null)
|
||||
return;
|
||||
|
||||
//Can't drag, return...
|
||||
if (!_reorderableList.IsDraggable)
|
||||
{
|
||||
_draggingObject = null;
|
||||
return;
|
||||
}
|
||||
|
||||
//If CloneDraggedObject just set draggingObject to this gameobject
|
||||
if (_reorderableList.CloneDraggedObject == false)
|
||||
{
|
||||
_draggingObject = _rect;
|
||||
_fromIndex = _rect.GetSiblingIndex();
|
||||
}
|
||||
//Else Duplicate
|
||||
else
|
||||
{
|
||||
GameObject clone = Instantiate(gameObject);
|
||||
_draggingObject = clone.GetComponent<RectTransform>();
|
||||
_draggingObject.sizeDelta = gameObject.GetComponent<RectTransform>().sizeDelta;
|
||||
}
|
||||
|
||||
//Put _dragging object into the draggin area
|
||||
_draggingObject.SetParent(_reorderableList.DraggableArea, false);
|
||||
_draggingObject.SetAsLastSibling();
|
||||
|
||||
//Create a fake element for previewing placement
|
||||
_fakeElement = new GameObject("Fake").AddComponent<RectTransform>();
|
||||
_fakeElement.gameObject.AddComponent<LayoutElement>().preferredHeight = _rect.rect.height;
|
||||
|
||||
|
||||
_isDragging = true;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!_isDragging)
|
||||
return;
|
||||
|
||||
//Set dragging object on cursor
|
||||
_draggingObject.position = eventData.position;
|
||||
|
||||
|
||||
//Check everything under the cursor to find a ReorderableList
|
||||
EventSystem.current.RaycastAll(eventData, _raycastResults);
|
||||
for (int i = 0; i < _raycastResults.Count; i++)
|
||||
{
|
||||
_currentReorderableListRaycasted = _raycastResults[i].gameObject.GetComponent<ReorderableList>();
|
||||
if (_currentReorderableListRaycasted != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//If nothing found or the list is not dropable, put the fake element outsite
|
||||
if (_currentReorderableListRaycasted == null || _currentReorderableListRaycasted.IsDropable == false)
|
||||
{
|
||||
_fakeElement.transform.SetParent(_reorderableList.DraggableArea, false);
|
||||
}
|
||||
//Else find the best position on the list and put fake element on the right index
|
||||
else
|
||||
{
|
||||
if (_fakeElement.parent != _currentReorderableListRaycasted)
|
||||
_fakeElement.SetParent(_currentReorderableListRaycasted.Content, false);
|
||||
|
||||
float minDistance = float.PositiveInfinity;
|
||||
int targetIndex = 0;
|
||||
for (int j = 0; j < _currentReorderableListRaycasted.Content.childCount; j++)
|
||||
{
|
||||
var c = _currentReorderableListRaycasted.Content.GetChild(j).GetComponent<RectTransform>();
|
||||
float dist = Mathf.Abs(c.position.y - eventData.position.y);
|
||||
|
||||
if (dist < minDistance)
|
||||
{
|
||||
minDistance = dist;
|
||||
targetIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
_fakeElement.SetSiblingIndex(targetIndex);
|
||||
_fakeElement.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
_isDragging = false;
|
||||
|
||||
if (_draggingObject != null)
|
||||
{
|
||||
//If we have a, ReorderableList that is dropable
|
||||
//Put the dragged object into the content and at the right index
|
||||
if (_currentReorderableListRaycasted != null && _currentReorderableListRaycasted.IsDropable)
|
||||
{
|
||||
_draggingObject.SetParent(_currentReorderableListRaycasted.Content, false);
|
||||
_draggingObject.SetSiblingIndex(_fakeElement.GetSiblingIndex());
|
||||
|
||||
//Send OnelementDropped Event
|
||||
_reorderableList.OnElementDropped.Invoke(new ReorderableList.ReorderableListEventStruct
|
||||
{
|
||||
DropedObject = _draggingObject.gameObject,
|
||||
IsAClone = _reorderableList.CloneDraggedObject,
|
||||
SourceObject = _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject,
|
||||
FromList = _reorderableList,
|
||||
FromIndex = _fromIndex,
|
||||
ToList = _currentReorderableListRaycasted,
|
||||
ToIndex = _fakeElement.GetSiblingIndex() - 1
|
||||
});
|
||||
}
|
||||
//We don't have an ReorderableList
|
||||
else
|
||||
{
|
||||
//If it's a clone, delete it
|
||||
if (_reorderableList.CloneDraggedObject)
|
||||
{
|
||||
Destroy(_draggingObject.gameObject);
|
||||
}
|
||||
//Else replace the draggedObject to his first place
|
||||
else
|
||||
{
|
||||
_draggingObject.SetParent(_reorderableList.Content, false);
|
||||
_draggingObject.SetSiblingIndex(_fromIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Delete fake element
|
||||
if (_fakeElement != null)
|
||||
Destroy(_fakeElement.gameObject);
|
||||
}
|
||||
|
||||
public void Init(ReorderableList reorderableList)
|
||||
{
|
||||
_reorderableList = reorderableList;
|
||||
_rect = GetComponent<RectTransform>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 916e98f1b982a9a4082fcc45c87b66c5
|
||||
timeCreated: 1446072130
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in New Issue