Drag and Drop components

Drag-and-Drop Support for the Collections

Different drag-and-drop components used with different widgets. Default widgets already have drag-and-drop components. For the generated widgets drag-and-drop components create automatically. Default Drag components usually attached to DefaultItem. Default Drop components usually attached to widgets and TreeView.DefaultItem.

Drag will be cancelled with OnCancel event from EventSystem (for example by pressing Esc).

You can remove drag-and-drop components from the widgets to disable drag-and-drop functionality.

Options

  • DragInfo: component to display the dragged data.
  • DragInfo Offset: offset from the cursor position.
  • Allow Drop Cursor: cursor when drop allowed.
  • Allow Drop Cursor Hot Spot: cursor hot spot.
  • Denied Drop Cursor: cursor when drop denies.
  • Denied Drop Cursor Hot Spot: cursor hot spot.
  • Default Cursor Texture: default cursor.
  • Default Drop Cursor Hot Spot: cursor hot spot.

Custom Drag Support

You can add own drag support with component inherited from DragSupport<TItem> implementation.

Methods

  • InitDrag (required): set Data value to drag
  • Dropped(bool success) (optional): what to do after the drop happened or canceled

Here is basic example of the drag support for the InputField:

namespace UIWidgets.Examples
{
   using UnityEngine;
   using UnityEngine.EventSystems;
   using UnityEngine.UI;

   /// <summary>
   /// Drag support for the InputField.
   /// </summary>
   [RequireComponent(typeof(InputField))]
   public class InputFieldDragSupportBase : DragSupport<string>
   {
      /// <summary>
      /// Set Data, which will be passed to the Drop component.
      /// </summary>
      /// <param name="eventData">Current event data.</param>
      protected override void InitDrag(PointerEventData eventData)
      {
         Data = GetComponent<InputField>().text;
      }
   }
}

This example show how to display draggable data:

namespace UIWidgets
{
   using UnityEngine;
   using UnityEngine.EventSystems;
   using UnityEngine.Serialization;
   using UnityEngine.UI;

   /// <summary>
   /// Drag support for the InputField.
   /// </summary>
   [RequireComponent(typeof(InputField))]
   public class InputFieldDragSupport : DragSupport<string>
   {
      /// <summary>
      /// Set Data, which will be passed to Drop component.
      /// </summary>
      /// <param name="eventData">Current event data.</param>
      protected override void InitDrag(PointerEventData eventData)
      {
         Data = GetComponent<InputField>().text;

         ShowDragInfo();
      }

      /// <summary>
      /// Called after the drop completed.
      /// </summary>
      /// <param name="success">true if Drop component received data; otherwise, false.</param>
      public override void Dropped(bool success)
      {
         HideDragInfo();

         base.Dropped(success);
      }

      /// <summary>
      /// Component to display draggable info.
      /// </summary>
      [SerializeField]
      public GameObject DragInfo;

      /// <summary>
      /// DragInfo offset.
      /// </summary>
      [SerializeField]
      [FormerlySerializedAs("LocalPosition")]
      public Vector3 DragInfoOffset = new Vector3(-5, 5, 0);

      /// <summary>
      /// Start this instance.
      /// </summary>
      protected virtual void Start()
      {
         if (DragInfo != null)
         {
            DragInfo.SetActive(false);
         }
      }

      /// <summary>
      /// Shows the drag info.
      /// </summary>
      protected virtual void ShowDragInfo()
      {
         if (DragInfo == null)
         {
            return;
         }

         DragInfo.transform.SetParent(DragPoint, false);
         DragInfo.transform.localPosition = DragInfoOffset;

         DragInfo.SetActive(true);

         DragInfo.GetComponentInChildren<Text>().text = Data;
      }

      /// <summary>
      /// Hides the drag info.
      /// </summary>
      protected virtual void HideDragInfo()
      {
         if (DragInfo == null)
         {
            return;
         }

         DragInfo.SetActive(false);
      }
   }
}

Custom Drop Support

You can add own the drop support with IDropSupport<TItem>> implementation.

Methods

  • CanReceiveDrop(TItem data, PointerEventData eventData): determine if the drop can be accepted or not, can used to display the drop preview.
  • Drop(TItem data, PointerEventData eventData): process the dropped data.
  • DropCanceled(TItem data, PointerEventData eventData): process the cancelled drop, can used to hide the drop preview.

Here is example code shows how to add TreeNode<TreeViewItem> and string drop support to the InputField, after drop InputField value would be set to the dropped node name or the dropped string.

CanReceiveDrop function allow to accept only nodes with names ends with 1.

namespace UIWidgets.Examples
{
   using UnityEngine;
   using UnityEngine.UI;
   using UnityEngine.EventSystems;

   /// <summary>
   /// TreeNode drop support for the InputField.
   /// </summary>
   [RequireComponent(typeof(InputField))]
   public class InputFieldDropSupport : MonoBehaviour, IDropSupport<TreeNode<TreeViewItem>>, IDropSupport<string>
   {
      #region IDropSupport<TreeNode<TreeViewItem>>

      /// <summary>
      /// Handle dropped data.
      /// </summary>
      /// <param name="data">Data.</param>
      /// <param name="eventData">Event data.</param>
      public void Drop(TreeNode<TreeViewItem> data, PointerEventData eventData)
      {
         GetComponent<InputField>().text = data.Item.Name;
      }

      /// <summary>
      /// Determines whether this instance can receive drop with the specified data and eventData.
      /// </summary>
      /// <returns>true if this instance can receive drop with the specified data and eventData; otherwise, false.</returns>
      /// <param name="data">Data.</param>
      /// <param name="eventData">Event data.</param>
      public bool CanReceiveDrop(TreeNode<TreeViewItem> data, PointerEventData eventData)
      {
         return data.Item.Name.EndsWith("1");
      }

      /// <summary>
      /// Handle canceled drop.
      /// </summary>
      /// <param name="data">Data.</param>
      /// <param name="eventData">Event data.</param>
      public void DropCanceled(TreeNode<TreeViewItem> data, PointerEventData eventData)
      {
      }

      #endregion

      #region IDropSupport<string>

      /// <summary>
      /// Handle dropped data.
      /// </summary>
      /// <param name="data">Data.</param>
      /// <param name="eventData">Event data.</param>
      public void Drop(string data, PointerEventData eventData)
      {
         GetComponent<InputField>().text = data;
      }

      /// <summary>
      /// Determines whether this instance can receive drop with the specified data and eventData.
      /// </summary>
      /// <returns>true if this instance can receive drop with the specified data and eventData; otherwise, false.</returns>
      /// <param name="data">Data.</param>
      /// <param name="eventData">Event data.</param>
      public bool CanReceiveDrop(string data, PointerEventData eventData)
      {
         return true;
      }

      /// <summary>
      /// Handle canceled drop.
      /// </summary>
      /// <param name="data">Data.</param>
      /// <param name="eventData">Event data.</param>
      public void DropCanceled(string data, PointerEventData eventData)
      {
      }

      #endregion
   }
}