Search Unity

Long press gesture on uGUI button?

Discussion in 'UGUI & 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:
    26
    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:
    254
    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
    longsl, AutoFire-II, dyupa and 6 others like this.
  5. junglemason

    junglemason

    Joined:
    Dec 30, 2010
    Posts:
    69
    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:
    51
    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.
     
  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();
    }
    }
     
  8. Khartraxx

    Khartraxx

    Joined:
    Mar 23, 2013
    Posts:
    1
    You can also set eligibleForClick to false on PointerEventData. You would need to keep the reference to it passed to OnPointerDown() method.

    Code (CSharp):
    1. public void OnPointerDown(PointerEventData eventData
    2. {
    3.     this.eventData = eventData;
    4.     Invoke("OnLongPress", holdTime);
    5. }
    6.  
    7. private void OnLongPress()
    8. {
    9.     eventData.eligibleForClick = false;
    10.     onLongPress.Invoke();
    11. }
     
    kaisersam likes this.
  9. stnaing

    stnaing

    Joined:
    Feb 25, 2019
    Posts:
    2
    in my case, OnLongPress calls only one time. how to make OnLongPress call as long as button pressed.
     
  10. GaggiGamer

    GaggiGamer

    Joined:
    Aug 10, 2020
    Posts:
    14
    Adding on....

    I don't know why these OnPointerHandlers are not getting triggered. Maybe I'm missing something important.
    But I found this very useful thing. So, you can instead AddComponent "Event Trigger" and there you can add different event types like OnPointerDown or many more and add functions to them like we do to OnClick() in editor.

    Edit : Also it is useful if you want to add a long press feature to a particular button/UI Object in unity

    Sorry for bad english.
     

    Attached Files:

    Last edited: Oct 24, 2020
  11. Porphy

    Porphy

    Joined:
    May 2, 2021
    Posts:
    1
    Use InvokeRepeating instead of Invoke