Touch and hold a button on new UI

Try using GUI.RepeatButton http://docs.unity3d.com/ScriptReference/GUI.RepeatButton.html

That is an imGUI function what they are doing in this post is uGUI. Your solution would work if this was not the case.

1 Like
[System.Serializable]
public enum eMovementDirection
{
    Up, Down, Left, Right
}
public class PointerListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    public eMovementDirection Direction;
  
    bool _pressed = false;
    public void OnPointerDown(PointerEventData eventData)
    {
        _pressed = true;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        _pressed = false;
    }

    void Update()
    {
        if (!_pressed)
            return;

        switch(Direction)
        {
            case eMovementDirection.Up:
                break;
              
            // (etc...)
      
        }
    }
}

[/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

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

2 Likes

Awesome Thanks!

1 Like

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!

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.

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.

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

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:

public class PointerListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
{
    public bool Pressed = false;

    public void OnPointerDown(PointerEventData eventData)
    {
        Pressed = true;
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        Pressed = true;
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        Pressed = false;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        Pressed = false;
    }
}

Attach this to your direction UI buttons (Left, Right…), and check the Pressed variable in your GuiManager.

Go to this answer, it worked really good for me, and its easier for me than the other solutions tey give, cuz you can see those on the properties painel…

well, just saying i prefered…

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!)

bool isPressed = false;
public void OnPointerDown(PointerEventData data) {       isPressed = true;  }
public void OnPointerUp(PointerEventData eventData) {    isPressed = false; }
public void OnPointerEnter(PointerEventData eventData) { if (Input.GetMouseButton(0)) isPressed = true;  }
public void OnPointerExit(PointerEventData eventData) {  isPressed = false; }
3 Likes

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);
}

}

2775376–200678–MobileButtons.cs (1.33 KB)

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.

public class UIButtonPress : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
{
    [HideInInspector]
    public bool Pressed = false;

    public UnityEvent onPressed;

    public void OnPointerDown(PointerEventData eventData)
    {
        Pressed = true;
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        Pressed = true;
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        Pressed = false;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        Pressed = false;
    }

    public void Update()
    {
        if (Pressed)
        {
            onPressed.Invoke();
        }
    }
}
1 Like

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));
}
}
}_

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.

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

public class MyButton : Button
{
    public void Update()
    {
        if(IsPressed())
        {
            onClick.Invoke ();
        }
    }

}


2 Likes

You answer was the first one that showing necessary interface implementation I was able to find so thank you so much really appreciated

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.

using UnityEngine;
using UnityEngine.EventSystems;

public class EventTriggerExample : EventTrigger
{
    public void OnBeginDrag(PointerEventData data)
    {
        Debug.Log("OnBeginDrag called.");
    }

    public void OnCancel(BaseEventData data)
    {
        Debug.Log("OnCancel called.");
    }

    public void OnDeselect(BaseEventData data)
    {
        Debug.Log("OnDeselect called.");
    }

    public void OnDrag(PointerEventData data)
    {
        Debug.Log("OnDrag called.");
    }

    public void OnDrop(PointerEventData data)
    {
        Debug.Log("OnDrop called.");
    }

    public void OnEndDrag(PointerEventData data)
    {
        Debug.Log("OnEndDrag called.");
    }

    public void OnInitializePotentialDrag(PointerEventData data)
    {
        Debug.Log("OnInitializePotentialDrag called.");
    }

    public void OnMove(AxisEventData data)
    {
        Debug.Log("OnMove called.");
    }

    public void OnPointerClick(PointerEventData data)
    {
        Debug.Log("OnPointerClick called.");
    }

    public void OnPointerDown(PointerEventData data)
    {
        Debug.Log("OnPointerDown called.");
    }

    public void OnPointerEnter(PointerEventData data)
    {
        Debug.Log("OnPointerEnter called.");
    }

    public void OnPointerExit(PointerEventData data)
    {
        Debug.Log("OnPointerExit called.");
    }

    public void OnPointerUp(PointerEventData data)
    {
        Debug.Log("OnPointerUp called.");
    }

    public void OnScroll(PointerEventData data)
    {
        Debug.Log("OnScroll called.");
    }

    public void OnSelect(BaseEventData data)
    {
        Debug.Log("OnSelect called.");
    }

    public void OnSubmit(BaseEventData data)
    {
        Debug.Log("OnSubmit called.");
    }

    public void OnUpdateSelected(BaseEventData data)
    {
        Debug.Log("OnUpdateSelected called.");
    }
}

The Script as found here: Redirecting to latest version of com.unity.ugui

Hi all!

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

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 :frowning: )

Any ideas?

1 Like