Search Unity

  1. Get all the Unite Berlin 2018 news on the blog.
    Dismiss Notice
  2. Unity 2018.2 has arrived! Read about it here.
    Dismiss Notice
  3. We're looking for your feedback on the platforms you use and how you use them. Let us know!
    Dismiss Notice
  4. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Learn more.
    Dismiss Notice
  6. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  7. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  8. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Long press gesture on uGUI button?

Discussion in 'Unity UI & TextMesh Pro' started by Krlker, Aug 25, 2014.

  1. Krlker

    Krlker

    Joined:
    Aug 25, 2014
    Posts:
    1
    I can only see OnClick() method on button.

    How to do a long press gesture on button or other gui elements?
    Just like in Windows 8 , a context menu will be shown when long press on some element.

    Or can OnClick() does send press duration to assigned method?

    Or can EventTrigger solve my problem?
     
    pixelPhil and John Azar like this.
  2. Gizmoi

    Gizmoi

    Joined:
    Jan 9, 2013
    Posts:
    327
    I would like to know this also, previously I've been doing it myself with my custom-rolled buttons. But ideally I'd like uGui to handle this. And swipes also ideally.
     
  3. ayrton2389

    ayrton2389

    Joined:
    Oct 25, 2013
    Posts:
    16
    I am also VERY interested in this. Is it possible with this new 4.6 gui system?

    Later edit:

    Ok, so i came up with a solution. Just implement the OnPointerUp and OnPointerDown events, use a bool to know if you`re pressing the button, and to the things you want when the button is pressed, in the Update loop. Very simple, actually.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.EventSystems;
    4.  
    5.  
    6. public class DirectionButton : MonoBehaviour,  IPointerDownHandler, IPointerUpHandler
    7. {
    8.     bool pressing = false;  
    9.     public PlayerController.ButtonsDirection dir;
    10.  
    11.     public void SetDirection()
    12.     {
    13.         PlayerController.Instance().buttonsDir = dir;
    14.     }
    15.  
    16.     public void OnPointerDown (PointerEventData eventData)
    17.     {
    18.         pressing = true;
    19.     }
    20.    
    21.    
    22.     public void OnPointerUp (PointerEventData eventData)
    23.     {
    24.         pressing = false;
    25.     }
    26.  
    27.     void Update()
    28.     {
    29.         if ( pressing )
    30.         {
    31.             // do continuous stuff here
    32.             SetDirection();
    33.         }
    34.     }
    35.  
    36. }
    37.  
     
    Last edited: Sep 14, 2014
  4. casimps1

    casimps1

    Joined:
    Jul 28, 2012
    Posts:
    253
    I feel like the OP's question was never quite answered and this thread seems to be the only one on the subject... so here's the component I built to handle long press events for context menus:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Events;
    3. using UnityEngine.EventSystems;
    4. using System.Collections;
    5.  
    6. public class LongPressEventTrigger : UIBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler {
    7.     [ Tooltip( "How long must pointer be down on this object to trigger a long press" ) ]
    8.     public float durationThreshold = 1.0f;
    9.  
    10.     public UnityEvent onLongPress = new UnityEvent( );
    11.  
    12.     private bool isPointerDown = false;
    13.     private bool longPressTriggered = false;
    14.     private float timePressStarted;
    15.  
    16.  
    17.     private void Update( ) {
    18.         if ( isPointerDown && !longPressTriggered ) {
    19.             if ( Time.time - timePressStarted > durationThreshold ) {
    20.                 longPressTriggered = true;
    21.                 onLongPress.Invoke( );
    22.             }
    23.         }
    24.     }
    25.  
    26.     public void OnPointerDown( PointerEventData eventData ) {
    27.         timePressStarted = Time.time;
    28.         isPointerDown = true;
    29.         longPressTriggered = false;
    30.     }
    31.  
    32.     public void OnPointerUp( PointerEventData eventData ) {
    33.         isPointerDown = false;
    34.     }
    35.  
    36.  
    37.     public void OnPointerExit( PointerEventData eventData ) {
    38.         isPointerDown = false;
    39.     }
    40. }
     
    Last edited: Jan 7, 2015
    dyupa, Aelcyx, oldSerge and 4 others like this.
  5. junglemason

    junglemason

    Joined:
    Dec 30, 2010
    Posts:
    66
    Works great. Thank you!

    Now I need to figure out: what's the most elegant way to prevent or ignore the subsequent Click event on a button that just invoked a LongPress event?

    Edit: I guess I just don't handle the Button's Click event, and instead modify this so that it invokes a Click if it's less than the long press time.
     
  6. TantzyGames

    TantzyGames

    Joined:
    Jul 27, 2016
    Posts:
    40
    Thanks casimps1, that code was really useful.

    The only problem is that I’ve been avoiding including any Update methods in my UI to keep it as speedy as possible, so I rewrote the long press script to avoid the Update method and it’s turned out to be a fair bit quicker as well:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Events;
    3. using UnityEngine.EventSystems;
    4.  
    5. public class ButtonLongPress : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler
    6. {
    7.     [SerializeField]
    8.     [Tooltip("How long must pointer be down on this object to trigger a long press")]
    9.     private float holdTime = 1f;
    10.  
    11.     //private bool held = false;
    12.     //public UnityEvent onClick = new UnityEvent();
    13.  
    14.     public UnityEvent onLongPress = new UnityEvent();
    15.  
    16.     public void OnPointerDown(PointerEventData eventData)
    17.     {
    18.         //held = false;
    19.         Invoke("OnLongPress", holdTime);
    20.     }
    21.  
    22.     public void OnPointerUp(PointerEventData eventData)
    23.     {
    24.         CancelInvoke("OnLongPress");
    25.  
    26.         //if (!held)
    27.         //    onClick.Invoke();
    28.     }
    29.  
    30.     public void OnPointerExit(PointerEventData eventData)
    31.     {
    32.         CancelInvoke("OnLongPress");
    33.     }
    34.  
    35.     void OnLongPress()
    36.     {
    37.         //held = true;
    38.         onLongPress.Invoke();
    39.     }
    40. }

    So what is this doing?

    Invoke calls a method after a certain number of seconds - in this case set by holdTime. The Invoke is cancelled if the mouse button is released or if the mouse leaves the button before the time is up. Not including an update method means there's no calculations every frame (and don't forget to remove all your empty update methods which still get added to the list).

    It's been my experience that adding this component to an existing button overrides the button’s onClick event if the long press is invoked. But I've noticed for some people the onClick event still occurs, so I included the ability for this component to handle all clicks - just remove the comment tags, and don't forget to remove the button's onClick action.

    One downside I’ve noticed is that if you add this to a lot of UI elements and then decide you want to change the default hold time in the script, Unity will have already serialized it on all those elements so changing it will have no effect.

    If that happens to you, you can either change it so it gets the value from a singleton or another solo class (in my case my MenuManager) or you can change the name of the holdTime field and the value. Then it will reset all those instances to your new value.
     
    Aelcyx likes this.
  7. Aqibsadiq

    Aqibsadiq

    Joined:
    Feb 20, 2015
    Posts:
    2
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.EventSystems;

    public class ButtonLongPress : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler
    {
    [SerializeField]
    [Tooltip("How long must pointer be down on this object to trigger a long press")]
    private float holdTime = 1f;

    // Remove all comment tags (except this one) to handle the onClick event!
    //private bool held = false;
    //public UnityEvent onClick = new UnityEvent();

    public UnityEvent onLongPress = new UnityEvent();

    public void OnPointerDown(PointerEventData eventData)
    {
    //held = false;
    Invoke("OnLongPress", holdTime);
    }

    public void OnPointerUp(PointerEventData eventData)
    {
    CancelInvoke("OnLongPress");

    //if (!held)
    // onClick.Invoke();
    }

    public void OnPointerExit(PointerEventData eventData)
    {
    CancelInvoke("OnLongPress");
    }

    private void OnLongPress()
    {
    //held = true;
    onLongPress.Invoke();
    }
    }