Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Touch and hold a button on new UI

Discussion in 'UGUI & TextMesh Pro' started by leandroreschke, Sep 2, 2014.

  1. leandroreschke

    leandroreschke

    Joined:
    Jan 8, 2014
    Posts:
    12
    I tried Click Event, and all the Events from Event Trigger Component, i can`t figure out how to make my 2D character walk when i hold the button, it just walk for a click, i`m using Rigidbody.AddForce, if i click a lot of times the Virtual D-Pad it walks, but i want it to be continuous, my script is not wrong because using WASD it work if i just click or hold down, but with the UI Button it just detect the click not if i hold.
     
    hopetolive and juned786 like this.
  2. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,037
    A click is down+up on a button. What you want is OnPointerDown() and OnPointerUp().
     
  3. FamerJoe

    FamerJoe

    Joined:
    Dec 21, 2013
    Posts:
    193
    Add an EventTrigger script to your button, and that will enable you to set callbacks for all the events.
     
  4. leandroreschke

    leandroreschke

    Joined:
    Jan 8, 2014
    Posts:
    12
    Can you explain how i use it, a guy said that i need to use OnPointerDown and OnPointerUp, to make a bool true and false.

    Now i`m using this

    public void WalkToLeft()
    {
    Rigidbody2D.AddForce(blablabla);
    }

    And call it from listener on click, every click it apply force to my 2D character, but i still not getting how i can make a bool with OnPointerDown/Up with Event Trigger Component. With old UI was easier to use GetTouch.phase == Stationary;
     
  5. peterdeghaim

    peterdeghaim

    Joined:
    Apr 10, 2014
    Posts:
    154
    You could trigger a bool on OnPointerDown which triggers a timer stored in the Update function
     
    leandroreschke likes this.
  6. leandroreschke

    leandroreschke

    Joined:
    Jan 8, 2014
    Posts:
    12
    yeah but the game actually will look every frame right, i was trying to avoid that, but ok so, can you just show me a code example of OnPointerDown?
     
  7. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,037
    The point of OnPointerDown() is that you only get it once before OnPointerUp() is sent. They're a single change of state, not a constant event.
     
  8. FamerJoe

    FamerJoe

    Joined:
    Dec 21, 2013
    Posts:
    193
    There's no code really, you have to attach an EventTrigger script to your object, and then click Add New and select OnPointDown from the list, then direct it to a function that will flip a bool, that if true will fire WalkToLeft from Update
     
  9. leandroreschke

    leandroreschke

    Joined:
    Jan 8, 2014
    Posts:
    12
    Thank you guys, now i understand it, and works pretty, thanks '-', was just that simple and i was complicating it, really thanks
     
    DonPuno likes this.
  10. peterdeghaim

    peterdeghaim

    Joined:
    Apr 10, 2014
    Posts:
    154
    The code may be a little messy but bare with me aha.

    Code (csharp):
    1.  
    2.  
    3. public static bool mouseDown;
    4. public float timeMouseDown;
    5.  
    6. void Update(){
    7.     if(mouseDown){
    8.        timeMouseDown += time.deltaTime;
    9. }
    10.  
    11. void OnPointerDown(){
    12.       mouseDown = true;
    13. }
    14. void OnPointerUp(){
    15.       mouseDown = false;
    16.       timeMouseDown = 0;
    17. }
    18.  
    19.  
    The code probably isn't functional cos i wrote this on a phone but you can use it as an example and it should help :)
     
  11. leandroreschke

    leandroreschke

    Joined:
    Jan 8, 2014
    Posts:
    12
    For Anyone looking for help and a working script here is mine

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerMovement : MonoBehaviour {
    5.     public float speed = 10.0f;
    6.     private bool walkUp;
    7.     private bool walkLeft;
    8.     private bool walkRight;
    9.     private bool walkDown;
    10.  
    11.     public void Update()
    12.     {
    13.         if (walkUp)
    14.         {
    15.             GetComponent<Rigidbody2D> ().AddForce (Vector2.up * speed);
    16.         }
    17.         else if (walkLeft)
    18.         {
    19.             GetComponent<Rigidbody2D> ().AddForce (-Vector2.right * speed);
    20.         }
    21.         else if (walkRight)
    22.         {
    23.             GetComponent<Rigidbody2D>().AddForce(Vector2.right * speed);
    24.         }
    25.         else if (walkDown)
    26.         {
    27.             GetComponent<Rigidbody2D>().AddForce(-Vector2.up * speed);
    28.         }
    29.     }
    30.     public void PlayerWalkUp(int value){
    31.         if (value == 1)
    32.         {
    33.             walkUp = true;
    34.         }
    35.         else
    36.         {
    37.             walkUp = false;
    38.         }
    39.  
    40.     }
    41.  
    42.     public void PlayerWalkLeft(int value){
    43.         if (value == 1)
    44.         {
    45.             walkLeft = true;
    46.         }
    47.         else
    48.         {
    49.             walkLeft = false;
    50.         }
    51.        
    52.     }
    53.  
    54.     public void PlayerWalkRight(int value){
    55.         if (value == 1)
    56.         {
    57.             walkRight = true;
    58.         }
    59.         else
    60.         {
    61.             walkRight = false;
    62.         }
    63.        
    64.     }
    65.  
    66.     public void PlayerWalkDown(int value){
    67.         if (value == 1)
    68.         {
    69.             walkDown = true;
    70.         }
    71.         else
    72.         {
    73.             walkDown = false;
    74.         }
    75.        
    76.     }
    77. }
    78.  
     
  12. Gurunext

    Gurunext

    Joined:
    Jan 23, 2013
    Posts:
    9
    It really bothered me that Unity didn't provide such an obvious function simply to know in what state button is... the solution up there does not work for mobile phones as they don't have pointers... so I found an akward solution:

    GetComponent<CanvasRenderer>().GetColor() == GetComponent<Button>().colors.pressedColor * GetComponent<Button>().colors.colorMultiplier

    if this is true then the button is active. Note that it has to be based on color change AND pressed color must be different from other colors to detect it. Not sure how it would work with animations or sprites. ALSO you could make an invissible same-shaped button just for the purpose of this kind of trigger detection.

    If someone designs a script that autamatically creates another image (that copies and sustains same important values) and tracks if it's triggered or not by returning a bool when asked (through the same method described above)... well post it here (unless I'll be forced to do it myself someday)
     
  13. JecoGames

    JecoGames

    Joined:
    Jan 10, 2013
    Posts:
    135
    Excuse me but how are you setting your event triggers for this, cant seem to get mine workking properly.
     
    Last edited: Dec 23, 2014
    allghoichorchoj likes this.
  14. K.sarattha

    K.sarattha

    Joined:
    Nov 14, 2013
    Posts:
    4
    Hey,I have a same problem as you .How can you solve it? I try to use event trigger to command to move gameobject by hold button by touch. Please help me!!
     
  15. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,688
    I've created a request on my UI Extensions repo to create a proper script that doesn't use EventTrigger. Bit ties up at the mo but should have it there in the next week. (https://bitbucket.org/ddreaper/unity-ui-extensions/issue/2/a-touch-and-hold-button)
    Reminder, EventTrigger should only be used if you REALLY have to, it is a very overweight component. For specific events, it is better to use the event interfaces to implement your behaviour.
     
    mandisaw likes this.
  16. BMayne

    BMayne

    Joined:
    Aug 4, 2014
    Posts:
    186
    As SimonDarksideJ was saying EventTrigger is super over kill for handling events. Just make your own classes or extend the default ones. If you extend the button class you can just do this.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. public class DownstateButton : Button
    6. {
    7.   public void Update()
    8.   {
    9. //A public function in the selectable class which button inherits from.
    10.     if(IsPressed())
    11.     {
    12.       WhilePressed();
    13.     }
    14.   }
    15.  
    16.   public void WhilePressed()
    17.   {
    18.     //Move your guys
    19.   }
    20. }
     
    Novack and BMRG14 like this.
  17. LunaticEdit

    LunaticEdit

    Joined:
    May 1, 2014
    Posts:
    60
    Code (CSharp):
    1. public class PointerListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
    2. {
    3.     bool _pressed = false;
    4.     public void OnPointerDown(PointerEventData eventData)
    5.     {
    6.         _pressed = true;
    7.     }
    8.  
    9.     public void OnPointerUp(PointerEventData eventData)
    10.     {
    11.         _pressed = false;
    12.     }
    13.  
    14.     void Update()
    15.     {
    16.         if (!_pressed)
    17.             return;
    18.  
    19.         // DO SOMETHING HERE
    20.     }
    21. }
    This is a component that will work on any ui object and handle the pointer down and up events. I'm not 100% sure if it properly handles dragging off of the object while pressed, but you can add an IPointerExitHandler and set pressed to false as well if you'd like.

    This solution does not require sub-classing the button object and can be added to all of the buttons. It also doesn't burn your cpu with needless Update calls. You could also add a public property for the direction the button represents. That way you can configure it visually in the inspector for each button, and have your code act upon the value dynamically:
    Code (CSharp):
    1. [System.Serializable]
    2. public enum eMovementDirection
    3. {
    4.     Up, Down, Left, Right
    5. }
    6. public class PointerListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
    7. {
    8.     public eMovementDirection Direction;
    9.    
    10.     bool _pressed = false;
    11.     public void OnPointerDown(PointerEventData eventData)
    12.     {
    13.         _pressed = true;
    14.     }
    15.  
    16.     public void OnPointerUp(PointerEventData eventData)
    17.     {
    18.         _pressed = false;
    19.     }
    20.  
    21.     void Update()
    22.     {
    23.         if (!_pressed)
    24.             return;
    25.  
    26.         switch(Direction)
    27.         {
    28.             case eMovementDirection.Up:
    29.                 break;
    30.                
    31.             // (etc...)
    32.        
    33.         }
    34.     }
    35. }
     
    cord42, BMRG14, galloper and 8 others like this.
  18. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,688
  19. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,243
    I have to comment in this thread just to say thanks & how useful the above is - not having an isPressed state in the UI button class is a huge omission in a game engine UI!
    I like BMayne's solution which I can only assume would not be very cpu intensive but I wouldn't know without trawling the UI code.
    But the 'isPressed' function is not even documented as far as I can see so is it only to be found by opening the UI source? This seems poor too.
     
    Ramcat likes this.
  20. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,243
    There is a problem with the above approaches for in-game input, namely if you do not start your touch ON the button, it will never register the button as down, so you can not slide between 2 buttons for left/right or up/down and you must tap accurately at the start of a press to hit it.
     
    Ramcat likes this.
  21. Redemuh

    Redemuh

    Joined:
    Sep 18, 2014
    Posts:
    1
    Try using GUI.RepeatButton http://docs.unity3d.com/ScriptReference/GUI.RepeatButton.html
     
  22. BMayne

    BMayne

    Joined:
    Aug 4, 2014
    Posts:
    186
    SimonDarksideJ likes this.
  23. prefix

    prefix

    Joined:
    Sep 26, 2011
    Posts:
    88
    Code (CSharp):
    1. [System.Serializable]
    2. public enum eMovementDirection
    3. {
    4.     Up, Down, Left, Right
    5. }
    6. public class PointerListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
    7. {
    8.     public eMovementDirection Direction;
    9.  
    10.     bool _pressed = false;
    11.     public void OnPointerDown(PointerEventData eventData)
    12.     {
    13.         _pressed = true;
    14.     }
    15.  
    16.     public void OnPointerUp(PointerEventData eventData)
    17.     {
    18.         _pressed = false;
    19.     }
    20.  
    21.     void Update()
    22.     {
    23.         if (!_pressed)
    24.             return;
    25.  
    26.         switch(Direction)
    27.         {
    28.             case eMovementDirection.Up:
    29.                 break;
    30.              
    31.             // (etc...)
    32.      
    33.         }
    34.     }
    35. }
    [/QUOTE]

    Which "namespace" (ie.. using UnityEngine) are you using? Im getting errors on IPointerDownHandler, IPointerUpHandler and PointerEventData eventData. Forgive my ignorance, im a beginner to coding.

    Im currently using:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;

    Thanks
     
  24. BMayne

    BMayne

    Joined:
    Aug 4, 2014
    Posts:
    186
    Which "namespace" (ie.. using UnityEngine) are you using? Im getting errors on IPointerDownHandler, IPointerUpHandler and PointerEventData eventData. Forgive my ignorance, im a beginner to coding.

    Im currently using:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;

    Thanks[/QUOTE]

    All the external ugui code is under their own name spaces.

    UnityEngine.UI
    UnityEngine.Events
    UnityEngine.Event systems

    I am pretty sure the last one is the one you want
     
    BMRG14 and prefix like this.
  25. prefix

    prefix

    Joined:
    Sep 26, 2011
    Posts:
    88
    Awesome Thanks!
     
    BMayne likes this.
  26. Foxxis

    Foxxis

    Joined:
    Jun 27, 2006
    Posts:
    1,108
    Ok, so these solutions will not work if the button press is triggered via a gamepad for example. Has anyone stumbled on that situation and a solution? Thanks!
     
  27. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,688
    New Well the currently supported input systems are geared around keyboard and mouse input.
    Gamepad support is driven mainly through the input manager mappings.

    Might be easier to build another "GamePad" specific input handler for GamePad games.
     
  28. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,688
    Lol, seems I didn't pick this up for the UIExtensions project. So I've extended the UIButton control in the 5.2 branch to expose a ButtonHeld event that fires for each frame that a button is held.
     
  29. Ash112

    Ash112

    Joined:
    Dec 9, 2015
    Posts:
    3
    Really confused.... I hav a button for acceleration bt its not like touch and hold but tap once.... I want to make it like touch and hold or like onkeydown and onkeyup.

    Like- unbutton down... Speed = 50
    Onbuttonup..... Speed=0.

    I need detailed answer step by step
     
    Last edited: Dec 13, 2015
  30. ttesla

    ttesla

    Joined:
    Feb 23, 2015
    Posts:
    16
    Yes, exactly. If you had two buttons Left and Right and if you drag your finger from Left button to Right button without releasing, it doesn't fire PointerDown event on Right button. As "prefix" said, we should consider OnEnter and OnExit events as well.

    So modifying the code a bit:
    Code (csharp):
    1.  
    2. public class PointerListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
    3. {
    4.     public bool Pressed = false;
    5.  
    6.     public void OnPointerDown(PointerEventData eventData)
    7.     {
    8.         Pressed = true;
    9.     }
    10.  
    11.     public void OnPointerEnter(PointerEventData eventData)
    12.     {
    13.         Pressed = true;
    14.     }
    15.  
    16.     public void OnPointerExit(PointerEventData eventData)
    17.     {
    18.         Pressed = false;
    19.     }
    20.  
    21.     public void OnPointerUp(PointerEventData eventData)
    22.     {
    23.         Pressed = false;
    24.     }
    25. }
    26.  
    Attach this to your direction UI buttons (Left, Right..), and check the Pressed variable in your GuiManager.
     
  31. andresandei

    andresandei

    Joined:
    Mar 12, 2014
    Posts:
    10
  32. DougMcFarlane

    DougMcFarlane

    Joined:
    Apr 25, 2009
    Posts:
    197
    Adding to @ttesla's post, my changes are for tracking only when the mouse is down.
    And it allows you to drag your mouse onto an object with the button already pressed.
    I only changed the OnPointerEnter() method.
    (I broke all the rules and tightened up the methods into one line - don't tell on me!)

    Code (CSharp):
    1. bool isPressed = false;
    2. public void OnPointerDown(PointerEventData data) {       isPressed = true;  }
    3. public void OnPointerUp(PointerEventData eventData) {    isPressed = false; }
    4. public void OnPointerEnter(PointerEventData eventData) { if (Input.GetMouseButton(0)) isPressed = true;  }
    5. public void OnPointerExit(PointerEventData eventData) {  isPressed = false; }
     
    ZiadJ, Rodolfo-Rubens and matvey007 like this.
  33. LilyStone

    LilyStone

    Joined:
    Sep 3, 2016
    Posts:
    1
    hey guys! I am new to these forums and mobile development and currently trying to make a mobile game for android. I currently have buttons made to where each time you click the player moves. My question is how would I make it so that the user would not need to press the button each time, just being able to touch and hold. My code for the buttons is shown here. Also my Game Object is a sphere, which I used to represent the player.


    using UnityEngine;
    using System.Collections;

    public class MobileButtons : MonoBehaviour
    {
    public GameObject player;

    // Use this for initialization
    void Start ()
    {

    }

    // Update is called once per frame
    void Update ()
    {

    }

    public void OnButtonClickUp()
    {
    player.transform.Translate(Vector3.forward * -10f * Time.deltaTime);
    }

    public void OnButtonClickDown()
    {
    player.transform.Translate(Vector3.back * -10f * Time.deltaTime);
    }

    public void OnButtonClickLeft()
    {
    player.transform.Translate(Vector3.left * -10f * Time.deltaTime);
    }

    public void OnButtonClickRight()
    {
    player.transform.Translate(Vector3.right * -10f * Time.deltaTime);
    }


    }
     

    Attached Files:

  34. Rainbirth

    Rainbirth

    Joined:
    Aug 3, 2013
    Posts:
    110
    Thanks very much for your solution.

    I added the UnityEvent so it behaves as a button you can snap any callback there in order to call it when pressing.

    Code (csharp):
    1.  
    2. public class UIButtonPress : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
    3. {
    4.     [HideInInspector]
    5.     public bool Pressed = false;
    6.  
    7.     public UnityEvent onPressed;
    8.  
    9.     public void OnPointerDown(PointerEventData eventData)
    10.     {
    11.         Pressed = true;
    12.     }
    13.  
    14.     public void OnPointerEnter(PointerEventData eventData)
    15.     {
    16.         Pressed = true;
    17.     }
    18.  
    19.     public void OnPointerExit(PointerEventData eventData)
    20.     {
    21.         Pressed = false;
    22.     }
    23.  
    24.     public void OnPointerUp(PointerEventData eventData)
    25.     {
    26.         Pressed = false;
    27.     }
    28.  
    29.     public void Update()
    30.     {
    31.         if (Pressed)
    32.         {
    33.             onPressed.Invoke();
    34.         }
    35.     }
    36. }
    37.  
     
    ar2r_f likes this.
  35. ulissescad

    ulissescad

    Joined:
    Oct 31, 2015
    Posts:
    14
    Hi guys, i have the same problem but use the script AxisTouchButton from standard assets attached to canvas Button and rename the axis from Vertical, Horizontal or someome. This soluction works very well for me. Thanks! Sorry for the poor english, not my native language.


    using System;
    using UnityEngine;
    using UnityEngine.EventSystems;

    namespace UnityStandardAssets.CrossPlatformInput
    {
    public class AxisTouchButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
    {
    // designed to work in a pair with another axis touch button
    // (typically with one having -1 and one having 1 axisValues)
    public string axisName = "Horizontal"; // The name of the axis
    public float axisValue = 1; // The axis that the value has
    public float responseSpeed = 3; // The speed at which the axis touch button responds
    public float returnToCentreSpeed = 3; // The speed at which the button will return to its centre

    AxisTouchButton m_PairedWith; // Which button this one is paired with
    CrossPlatformInputManager.VirtualAxis m_Axis; // A reference to the virtual axis as it is in the cross platform input

    void OnEnable()
    {
    if (!CrossPlatformInputManager.AxisExists(axisName))
    {
    // if the axis doesnt exist create a new one in cross platform input
    m_Axis = new CrossPlatformInputManager.VirtualAxis(axisName);
    CrossPlatformInputManager.RegisterVirtualAxis(m_Axis);
    }
    else
    {
    m_Axis = CrossPlatformInputManager.VirtualAxisReference(axisName);
    }
    FindPairedButton();
    }

    void FindPairedButton()
    {
    // find the other button witch which this button should be paired
    // (it should have the same axisName)
    var otherAxisButtons = FindObjectsOfType(typeof(AxisTouchButton)) as AxisTouchButton[];

    if (otherAxisButtons != null)
    {
    for (int i = 0; i < otherAxisButtons.Length; i++)
    {
    if (otherAxisButtons.axisName == axisName && otherAxisButtons != this)
    {
    m_PairedWith = otherAxisButtons;
    }
    }
    }
    }

    void OnDisable()
    {
    // The object is disabled so remove it from the cross platform input system
    m_Axis.Remove();
    }


    public void OnPointerDown(PointerEventData data)
    {
    if (m_PairedWith == null)
    {
    FindPairedButton();
    }
    // update the axis and record that the button has been pressed this frame
    m_Axis.Update(Mathf.MoveTowards(m_Axis.GetValue, axisValue, responseSpeed * Time.deltaTime));
    }


    public void OnPointerUp(PointerEventData data)
    {
    m_Axis.Update(Mathf.MoveTowards(m_Axis.GetValue, 0, responseSpeed * Time.deltaTime));
    }
    }
    }
     
  36. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,197
    But them the OnPointerUp is not going to be called because the click started in another game object, how to fix this?

    Sorry to bump an old thread.
     
  37. atifmahmood29

    atifmahmood29

    Joined:
    Nov 23, 2014
    Posts:
    8
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. public class MyButton : Button
    6. {
    7.     public void Update()
    8.     {
    9.         if(IsPressed())
    10.         {
    11.             onClick.Invoke ();
    12.         }
    13.     }
    14.  
    15. }
    16.  

     
    unity_8889rax and Eltaris like this.
  38. berk_can

    berk_can

    Joined:
    Feb 8, 2016
    Posts:
    15
    You answer was the first one that showing necessary interface implementation I was able to find so thank you so much really appreciated
     
  39. Rispat-Momit

    Rispat-Momit

    Joined:
    Feb 14, 2013
    Posts:
    265
    Just add this script on your UI Button to extend the possibilities and functions of your UI Button for some reason the call override that existed in the void was disabling everything.


    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.EventSystems;
    3.  
    4. public class EventTriggerExample : EventTrigger
    5. {
    6.     public void OnBeginDrag(PointerEventData data)
    7.     {
    8.         Debug.Log("OnBeginDrag called.");
    9.     }
    10.  
    11.     public void OnCancel(BaseEventData data)
    12.     {
    13.         Debug.Log("OnCancel called.");
    14.     }
    15.  
    16.     public void OnDeselect(BaseEventData data)
    17.     {
    18.         Debug.Log("OnDeselect called.");
    19.     }
    20.  
    21.     public void OnDrag(PointerEventData data)
    22.     {
    23.         Debug.Log("OnDrag called.");
    24.     }
    25.  
    26.     public void OnDrop(PointerEventData data)
    27.     {
    28.         Debug.Log("OnDrop called.");
    29.     }
    30.  
    31.     public void OnEndDrag(PointerEventData data)
    32.     {
    33.         Debug.Log("OnEndDrag called.");
    34.     }
    35.  
    36.     public void OnInitializePotentialDrag(PointerEventData data)
    37.     {
    38.         Debug.Log("OnInitializePotentialDrag called.");
    39.     }
    40.  
    41.     public void OnMove(AxisEventData data)
    42.     {
    43.         Debug.Log("OnMove called.");
    44.     }
    45.  
    46.     public void OnPointerClick(PointerEventData data)
    47.     {
    48.         Debug.Log("OnPointerClick called.");
    49.     }
    50.  
    51.     public void OnPointerDown(PointerEventData data)
    52.     {
    53.         Debug.Log("OnPointerDown called.");
    54.     }
    55.  
    56.     public void OnPointerEnter(PointerEventData data)
    57.     {
    58.         Debug.Log("OnPointerEnter called.");
    59.     }
    60.  
    61.     public void OnPointerExit(PointerEventData data)
    62.     {
    63.         Debug.Log("OnPointerExit called.");
    64.     }
    65.  
    66.     public void OnPointerUp(PointerEventData data)
    67.     {
    68.         Debug.Log("OnPointerUp called.");
    69.     }
    70.  
    71.     public void OnScroll(PointerEventData data)
    72.     {
    73.         Debug.Log("OnScroll called.");
    74.     }
    75.  
    76.     public void OnSelect(BaseEventData data)
    77.     {
    78.         Debug.Log("OnSelect called.");
    79.     }
    80.  
    81.     public void OnSubmit(BaseEventData data)
    82.     {
    83.         Debug.Log("OnSubmit called.");
    84.     }
    85.  
    86.     public void OnUpdateSelected(BaseEventData data)
    87.     {
    88.         Debug.Log("OnUpdateSelected called.");
    89.     }
    90. }

    The Script as found here: https://docs.unity3d.com/ScriptReference/EventSystems.EventTrigger.html
     
    Last edited: Jul 12, 2018
  40. Game-Armada

    Game-Armada

    Joined:
    Apr 29, 2013
    Posts:
    66
    Hi all!

    Any working solution for this issue so far? None of the above works with all the conditions needed :(

    Conditions:
    - pressed if you click and hold the button
    - unpressed if you hold down mouse and leave the button
    - pressed if you click and hold outside the button and move you pointer/finger on the button so it becomes pressed
    - pressed when other button pressed and the pointer / finger slides to our button

    (of course one can check the position of the pointer, but then you don't need Unity UI at all for that :( )

    Any ideas?
     
    Shorely likes this.
  41. shacharoz

    shacharoz

    Joined:
    Jul 11, 2013
    Posts:
    98
    i have used some code from the above answers and integrated it into one solution.

    create 2 classes:

    add both to the Button. remove the original Button script beforehand.
    on the ButtonActions, which you can easily extend, you can fill the rest of your events.


    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.Events;
    4.  
    5. public class ButtonActions : MonoBehaviour
    6. {
    7.     public UnityEvent OnButtonDown;
    8.  
    9.     public void Pressed()
    10.     {
    11.         OnButtonDown.Invoke();
    12.     }
    13.  
    14.     public void Released()
    15.     {
    16.     }
    17. }
    18.  


    Code (CSharp):
    1. using UnityEngine;
    2.  
    3.  
    4. [RequireComponent(typeof(ButtonActions))]
    5. public class DownPressedButton : UnityEngine.UI.Button
    6. {
    7.     private ButtonActions actionsHolder;
    8.  
    9.     private void Update()
    10.     {
    11.         //IsPressed is a public function in the selectable class which button inherits from.
    12.         if (IsPressed())
    13.         {
    14.             WhilePressed();
    15.         }
    16.     }
    17.  
    18.     /// <summary>
    19.     /// invoke an event while the button is pressed
    20.     /// </summary>
    21.     public void WhilePressed()
    22.     {
    23.         if (actionsHolder == null)
    24.         {
    25.             actionsHolder = GetComponent<ButtonActions>();
    26.         }
    27.         actionsHolder.Pressed();
    28.     }
    29. }
     
  42. AdamBebko

    AdamBebko

    Joined:
    Apr 8, 2016
    Posts:
    164
    For new UIToolkit, here's a solution I figured out

    Code (CSharp):
    1.  
    2.  
    3. public class ButtonClickStateManager {
    4.  
    5.         public bool isDown = false;
    6.      
    7.         public ButtonClickStateManager(Button button, bool enableLeftMouseButton = true) {
    8.             button.RegisterCallback<PointerDownEvent>(evt => ButtonClicked());
    9.             button.RegisterCallback<PointerUpEvent>(evt => ButtonNotClicked());
    10.             button.RegisterCallback<PointerLeaveEvent>(evt => ButtonNotClicked());
    11.  
    12.             if (enableLeftMouseButton) {
    13.                 //need this for left mouse button to work for some reason
    14.                 button.clickable.activators.Clear();
    15.             }
    16.          
    17.         }
    18.  
    19.         void ButtonClicked() {
    20.             isDown = true;
    21.         }
    22.  
    23.         void ButtonNotClicked() {
    24.             isDown = false;
    25.         }
    26. }
    27.  
    then initialize it like so it like so:


    Code (CSharp):
    1.  
    2. var rightButton = bottomBar.Q<Button>("rotate-right");
    3. rightButtonState = new ButtonClickStateManager(rightButton);
    Then you can see if the button is held down elsewhere in your code like so:

    Code (CSharp):
    1.  
    2. if (rightButtonState.isDown) BaseController.RotateRight();
    3.  
    This seems overly complicated for something as simple as a button hold.. but this is the best solution I've found yet. It works on IOS too.
     
  43. IvanIvanovP3

    IvanIvanovP3

    Joined:
    Jan 24, 2021
    Posts:
    6
    what is it "enableLeftMouseButton"? and "some reason"?
     
  44. AdamBebko

    AdamBebko

    Joined:
    Apr 8, 2016
    Posts:
    164
    The "for some reason" means I have no clue.

    By default this solution doesn't work for the left mouse button. The bool is if you want to click with the left mouse button. For some reason (I don't know why), that extra step is needed to enable it. Not sure why they make this simple task so hard on us.
     
  45. Garazbolg

    Garazbolg

    Joined:
    Oct 19, 2014
    Posts:
    2
    Seeing that this thread has been resurected and that multiple solution suggest using the Update method (performance black hole guys, don't do that) here is my implementation :



    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4. using UnityEngine.EventSystems;
    5. using UnityEngine.Events;
    6.  
    7. public class ButtonWithHold : Selectable
    8. {
    9.     [Header("Settings")]
    10.     [SerializeField] private float holdTime = .5f;
    11.  
    12.     [Header("Callbacks")]
    13.     public UnityEvent onClick;
    14.     public UnityEvent onHold;
    15.  
    16.     private Coroutine coroutine = null;
    17.     private float holdStart = 0f;
    18.     private bool Started = false;
    19.  
    20.  
    21.     #region Pointers Handlers
    22.     public override void OnPointerDown(PointerEventData eventData)
    23.     {
    24.         base.OnPointerDown(eventData);
    25.         StartHold();
    26.     }
    27.  
    28.     public override void OnPointerUp(PointerEventData eventData)
    29.     {
    30.         base.OnPointerUp(eventData);
    31.         if (!Input.GetMouseButton(0))
    32.             StopHold();
    33.     }
    34.  
    35.     public override void OnPointerExit(PointerEventData eventData)
    36.     {
    37.         base.OnPointerExit(eventData);
    38.         ResetHold();
    39.     }
    40.     #endregion
    41.  
    42.     #region Hold Management
    43.     private void StartHold()
    44.     {
    45.         ResetHold();
    46.         holdStart = Time.realtimeSinceStartup;
    47.         coroutine = StartCoroutine(CO_HoldTimer());
    48.         Started = true;
    49.     }
    50.  
    51.     private void StopHold()
    52.     {
    53.         if (Started)
    54.         {
    55.             if (Time.realtimeSinceStartup - holdStart > holdTime)
    56.             {
    57.                 onHold.Invoke();
    58.             }
    59.             else
    60.             {
    61.                 onClick.Invoke();
    62.             }
    63.         }
    64.         ResetHold();
    65.         holdStart = Time.realtimeSinceStartup;
    66.     }
    67.  
    68.     private void ResetHold()
    69.     {
    70.         if (coroutine != null)
    71.         {
    72.             StopCoroutine(coroutine);
    73.             coroutine = null;
    74.         }
    75.         Started = false;
    76.     }
    77.  
    78.     private IEnumerator CO_HoldTimer()
    79.     {
    80.         yield return new WaitForSecondsRealtime(holdTime);
    81.         StopHold();
    82.     }
    83.  
    84.     protected override void OnDestroy()
    85.     {
    86.         ResetHold();
    87.     }
    88.     #endregion
    89. }
    It shows just like a button with all the option you're used to finding. The only difference is that it has a Hold Time property and a OnHold Event. This is how I think most people want to use it. Hope it helps some of you despite the age of this thread.
     
    andbastin likes this.