Search Unity

List: Order Items by dragging

Discussion in 'UGUI & TextMesh Pro' started by ruffyD, Feb 28, 2015.

  1. ruffyD

    ruffyD

    Joined:
    Dec 11, 2014
    Posts:
    13
    Hey guys,

    I have a list setup as follows:

    ScrollRect / Mask
    --Content Size Fitter / Vertical Layout Group
    ----LayoutElement 1
    ...
    ----LayoutElement N

    Now, I want to be able to drag one item and pull it up or downwards in order to change its position in the list.
    I don't know how to do this. I tried a lot of things, but It would be great if someone could point me to the right direction. I googled a lot, nobody seems to have this desire?
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I'm not yet familiar enough with the UI to know what sort of editor components might be helpful for that, but I did notice that the Supported Events List includes entires for Drag, EndDrag, and Drop, so failing all else you could write your own scripts that respond to those events and call Transform.SetSiblingIndex (or SetAsFirstSibling and SetAsLastSibling) to change the order of your objects.
     
  3. ruffyD

    ruffyD

    Joined:
    Dec 11, 2014
    Posts:
    13
    Okay, so I am not quite sure how to use those events (other than assigning a listener to a callback).
    Would I need to write my own object, which extends LayoutElement and implements those Interfaces?

    //Edit: Besides that: changing the order of the items in the hirachy solves for a good result, however it isn't possible to show a user that he/she is currently "moving" the element.
     
  4. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Right @ruffyD such a setup would be quite complicated to get going. @Antistone points out quite rightly that you would need to write some scripts using the Pointer and Drag handler interfaces, then attach these to objects to pick them up and move them, that part is quite simple.
    The hard part is putting them back down again, raycasting to the underlying list to figure the current sibling index of the item you are over and then temporarily placing the new item before/after it, then finishing when the user releases the pointer (DragEnd).

    A good example of the drag and drop scripts can be found in the UI Samples asset that UT provide. They will give you some hints as to where to start: https://www.assetstore.unity3d.com/en/#!/content/25468

    Hope this helps
     
  5. ruffyD

    ruffyD

    Joined:
    Dec 11, 2014
    Posts:
    13
    Thank you @SimonDarksideJ! I appreciate that.
    Still, a bummer that something that is that common in today's user interfaces is lacking as a readily available tool.
     
    thecloudkeeper likes this.
  6. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Like so many things, there are literally millions of controls and variants out there and UT can't be expected to provide them all :D

    Which is why I created the UI Extensions bitbucket repo for the community to build controls and share them through a single project :D (link below) already a lot of controls / extensions and effects in there.
    If you build it, feel free to submit it :D
     
  7. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I decided to take a quick crack at this.

    Add this component to a container object. (The container should also have some sort of layout component, such as a VerticalLayoutGroup.)
    Code (CSharp):
    1. using UnityEngine;
    2. public class DragOrderContainer : MonoBehaviour {
    3.  
    4.     public GameObject objectBeingDragged { get; set; }
    5.  
    6.     void Awake () {
    7.         objectBeingDragged = null;
    8.     }
    9. }
    Then add this component to each of the objects inside the container:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.EventSystems;
    4.  
    5. public class DragOrderObject : MonoBehaviour, IPointerEnterHandler, IBeginDragHandler, IDragHandler, IEndDragHandler {
    6.  
    7.     DragOrderContainer container = null;
    8.  
    9.     void Start () {
    10.         container = GetComponentInParent<DragOrderContainer>();
    11.     }
    12.  
    13.     public void OnBeginDrag(PointerEventData eventData)
    14.     {
    15.         container.objectBeingDragged = this.gameObject;
    16.     }
    17.     public void OnDrag(PointerEventData data)
    18.     {
    19.         // Do nothing
    20.         // Apparently this interface needs to exist in order for BeginDrag and EndDrag to work,
    21.         // but we don't actually have anything to do here
    22.     }
    23.     public void OnEndDrag(PointerEventData eventData)
    24.     {
    25.         if (container.objectBeingDragged == this.gameObject) container.objectBeingDragged = null;
    26.     }
    27.  
    28.     public void OnPointerEnter(PointerEventData eventData)
    29.     {
    30.         GameObject objectBeingDragged = container.objectBeingDragged;
    31.         if (objectBeingDragged != null && objectBeingDragged != this.gameObject)
    32.         {
    33.             objectBeingDragged.transform.SetSiblingIndex(this.transform.GetSiblingIndex());
    34.         }
    35.     }
    36. }
    Seems to work for me in a simple test case.
     
  8. ruffyD

    ruffyD

    Joined:
    Dec 11, 2014
    Posts:
    13
    Wow thanks @Antistone!

    I'll check it out later.
    Great community ;)
     
  9. adamers

    adamers

    Joined:
    Apr 2, 2014
    Posts:
    5
    How can i save order of gameobject in playerprefs like that ? ?
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Saveposition : MonoBehaviour {
    6.  
    7.    public GameObject[] InputFields;
    8.  
    9.  
    10.     void Awake()
    11.  
    12.     {
    13.  
    14.         for (int i = 0; i < InputFields.Length; i++)
    15.         {
    16.             InputFields[i].text = PlayerPrefs.GetString(InputFields[i].name);
    17.          
    18.         }
    19.    
    20.     }
    21.  
    22.  
    23.     private void OnApplicationQuit()
    24.     {
    25.         for (int i = 0; i < InputFields.Length; i++)
    26.         {
    27.             PlayerPrefs.SetString(InputFields[i].name, InputFields[i].text);
    28.             PlayerPrefs.Save();
    29.         }
    30.  
    31.     }
    32.  
    33.     private void OnApplicationPause(bool pause)
    34.     {
    35.  
    36.  
    37.         for (int i = 0; i < InputFields.Length; i++)
    38.         {
    39.             PlayerPrefs.SetString(InputFields[i].name, InputFields[i].text);
    40.             PlayerPrefs.Save();
    41.         }
    42.  
    43.  
    44.     }
    45.  
    46.  
    47. }
     
    Last edited: Sep 19, 2017
  10. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
  11. Alpha_Den

    Alpha_Den

    Joined:
    Jun 16, 2016
    Posts:
    2
    @adamers Dude you are the best it really worked and I have been working on it for a long time. Thank you so much.