Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
4
Question by Xarbrough · Aug 08, 2016 at 08:47 PM · c#buttonevent

AddListener to OnPointerDown of Button instead of onClick

I'd like to register a callback to the OnPointerDown and OnPointerUp events of the UnityEngine.UI.Button(s) in my game to trigger two different sounds for down and up click. However, only the onClick event is exposed. Is there any clean method to get these properties through code? I'd rather not add the UnityEngine.EventTrigger component to every button individually and set them up in the scene, because of the amount of buttons in my project and I might want to change behaviour while testing, and therefore rather do it from one central location in code.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
16
Best Answer

Answer by Xarbrough · Aug 09, 2016 at 07:10 PM

I was expecting this to be built into the Unity button component, because it's such a common thing to ask for when assigning sounds to buttons and also the button must use it's OnPointerDown event internally to trigger sprite transitions etc. Why wouldn't they just expose these callback publicly like onClick already is?

Anyway, here is my code that got it working:

 EventTrigger trigger = buttons[i].gameObject.AddComponent<EventTrigger>();
 var pointerDown = new EventTrigger.Entry();
 pointerDown.eventID = EventTriggerType.PointerDown;
 pointerDown.callback.AddListener((e) => AkSoundEngine.PostEvent(downEvent, gameObject));
 trigger.triggers.Add(pointerDown);

For every button that needs additional listeners, I add an EventTrigger component and the appropriate PointerDown EventTriggerType. This has much more overhead than I wanted it to have, but it still works better than adding sound components to 20 buttons manually.

PS: Of course, I'd still be interested in seeing a better solution than mine.

Edit - Custom UI Button

I just figured, that I could also subclass the existing Unity Button to add my desired functionality. I keep forgetting that the UI source is extendable. This works very well and feels much cleaner. Just to spread community knowledge, here is my button extension, which I use to later add two different click sounds for down and up.

 using UnityEngine;
 using UnityEngine.UI;
 using UnityEngine.Events;
 using UnityEngine.EventSystems;
 using System;
 
 // Button that raises onDown event when OnPointerDown is called.
 [AddComponentMenu("Aeronauts/AeButton")]
 public class AeButton : Button
 {
     // Event delegate triggered on mouse or touch down.
     [SerializeField]
     ButtonDownEvent _onDown = new ButtonDownEvent();
 
     protected AeButton() { }
 
     public override void OnPointerDown(PointerEventData eventData)
     {
         base.OnPointerDown(eventData);
 
         if (eventData.button != PointerEventData.InputButton.Left)
             return;
 
         _onDown.Invoke();
     }
 
     public ButtonDownEvent onDown
     {
         get { return _onDown; }
         set { _onDown = value; }
     }
 
     [Serializable]
     public class ButtonDownEvent : UnityEvent { }
 }    

To make the ButtonDownEvent also show up in the inspector, you will need to subclass the according ButtonEditor as well.

 using UnityEditor;
 using UnityEditor.UI;
 
 [CustomEditor(typeof(AeButton), true)]
 public class AeButtonEditor : ButtonEditor
 {
     SerializedProperty _onDownProperty;
 
     protected override void OnEnable()
     {
         base.OnEnable();
         _onDownProperty = serializedObject.FindProperty("_onDown");
     }
 
     public override void OnInspectorGUI()
     {
         base.OnInspectorGUI();
         EditorGUILayout.Space();
 
         serializedObject.Update();
         EditorGUILayout.PropertyField(_onDownProperty);
         serializedObject.ApplyModifiedProperties();
     }
 }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image giantguppy · Jun 13, 2019 at 06:23 PM 1
Share

This answer really helped me but I found it a bit overkill. I don't need to serialize my UI elements, and I don't need setters for my events, and I don't need a custom 'ButtonDownEvent' class, and I don't need to filter mouse buttons for mobile platforms. So here's my simplified version which also handles button-up:

 using UnityEngine;
 using UnityEngine.Events;
 using UnityEngine.EventSystems;
 using UnityEngine.UI;
 using System;
 
 [AddComponent$$anonymous$$enu("UI/$$anonymous$$yButton")]
 public class $$anonymous$$yButton : Button
 {
     UnityEvent mOnDown = new UnityEvent();
     UnityEvent mOnUp = new UnityEvent();
 
     public override void OnPointerDown(PointerEventData eventData)
     {
         base.OnPointerDown(eventData);
         mOnDown.Invoke();
     }
 
     public override void OnPointerUp(PointerEventData eventData)
     {
         base.OnPointerUp(eventData);
         mOnUp.Invoke();
     }
 
     public UnityEvent onDown
     {
         get{ return mOnDown; }
     }
     
     public UnityEvent onUp
     {
         get{ return mOnUp; }
     }
 }
 
avatar image
7

Answer by RyanShackelford · Apr 25, 2018 at 11:16 PM

A simple way to add any event to an item via the Unity Editor is by adding an "Event Trigger" Component to any GameObject.

Just select your button, at the bottom, select "Add Component", add the "Event Trigger", then select "Add New Event Type", select Pointer Down, then select Pointer Down or any other events you need.

Then drag in the script or GameObject with a script attached. The script will need to have a public function that will be called when the event is triggered. Select it from the Dropdown, and your event is ready to run!

Much easier than creating a whole new script to manage events when the generic events work.

Many thanks to this YouTuber for revealing this little gem to me. (Not in English) https://www.youtube.com/watch?v=XmNdu1O22hs

--Ryan

https://answers.unity.com/questions/537207/choppy-camera-follow.html try in the Update thread if your game logic for movement is used in Update.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Jortei · Sep 11, 2019 at 03:32 AM 0
Share

This answer was especially useful for buttons in android mobile games. Thanks!

avatar image CringeItIn · May 28, 2021 at 11:21 AM 0
Share

Exactly what I was looking for, thanks you!

avatar image Grey_Haven · Jul 26, 2021 at 09:59 PM 0
Share

You're the mvp. I didn't know about event triggers until today and they've actually solved a lot of problems I'm working on today.

avatar image
1

Answer by DavidJares · Feb 21, 2019 at 06:51 AM

Hey Guys. Thanks for your input. I made an Extension Method out of it for my purposes.

 public static EventTrigger AddTriggersEvents(this Selectable theSelectable, EventTriggerType eventTriggerType, Action<BaseEventData> onTriggerAction = null)
 {
     EventTrigger eventrTrigger = theSelectable.gameObject.AddComponent<EventTrigger>();
     if (onTriggerAction != null)
     {
         EventTrigger.Entry pointerEvent = new EventTrigger.Entry();
         pointerEvent.eventID = eventTriggerType;
         pointerEvent.callback.AddListener((x) => onTriggerAction(x));
         eventrTrigger.triggers.Add(pointerEvent);
     }
     return eventrTrigger;
 }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by LocDogg · Jul 25, 2018 at 08:33 PM

Both solutions suggested by Xarbrough are very good. I took the first and ran with it.

The inheritance solution is better if you don't already have tons of UI elements to deal with. If you do, it requires replacing scripts and reconfiguring from scratch in Unity UI. Those settings wont copy and paste. Maybe in the past I've done that the wrong way, but I recall it being pretty rough.

IMyInterface and MyInterfaceMethod are pseudo code. The rest is theoretically functional, but could use some optimization:

 using UnityEngine;
 using UnityEngine.EventSystems;
 using UnityEngine.UI;
 
 public class LockInputComponent : MonoBehaviour, IMyInterface {
     private Button[] buttons;
     private InputField[] inputFields;
     private Slider[] sliders;
     private Toggle[] toggles;
 
     void Start () {
         buttons = GetComponentsInChildren<Button> (true);
         inputFields = GetComponentsInChildren<InputField> (true);
         sliders = GetComponentsInChildren<Slider> (true);
         toggles = GetComponentsInChildren<Toggle> (true);
 
         AddListeners ();
     }
 
     private void AddListeners () {
         for (int i = 0; i < buttons.Length; i++) {
             EventTrigger triggerDown = buttons[i].gameObject.AddComponent<EventTrigger> ();
             var pointerDown = new EventTrigger.Entry ();
             pointerDown.eventID = EventTriggerType.PointerDown;
             pointerDown.callback.AddListener ((e) => MyInterfaceMethod (true));
             triggerDown.triggers.Add (pointerDown);
 
             EventTrigger triggerUp = buttons[i].gameObject.AddComponent<EventTrigger> ();
             var pointerUp = new EventTrigger.Entry ();
             pointerUp.eventID = EventTriggerType.PointerUp;
             pointerUp.callback.AddListener ((e) => MyInterfaceMethod (false));
             triggerUp.triggers.Add (pointerUp);
         }
 
         for (int i = 0; i < inputFields.Length; i++) {
             EventTrigger triggerBeginEdit = inputFields[i].gameObject.AddComponent<EventTrigger> ();
             var pointerDown = new EventTrigger.Entry ();
             pointerDown.eventID = EventTriggerType.PointerEnter;
             pointerDown.callback.AddListener ((e) => MyInterfaceMethod (true));
             triggerBeginEdit.triggers.Add (pointerDown);
 
             EventTrigger triggerEndEdit = inputFields[i].gameObject.AddComponent<EventTrigger> ();
             var pointerUp = new EventTrigger.Entry ();
             pointerUp.eventID = EventTriggerType.PointerExit;
             pointerUp.callback.AddListener ((e) => MyInterfaceMethod (false));
             triggerEndEdit.triggers.Add (pointerUp);
         }
 
         for (int i = 0; i < sliders.Length; i++) {
             EventTrigger triggerDown = sliders[i].gameObject.AddComponent<EventTrigger> ();
             var pointerDown = new EventTrigger.Entry ();
             pointerDown.eventID = EventTriggerType.PointerDown;
             pointerDown.callback.AddListener ((e) => MyInterfaceMethod (true));
             triggerDown.triggers.Add (pointerDown);
 
             EventTrigger triggerUp = sliders[i].gameObject.AddComponent<EventTrigger> ();
             var pointerUp = new EventTrigger.Entry ();
             pointerUp.eventID = EventTriggerType.PointerUp;
             pointerUp.callback.AddListener ((e) => MyInterfaceMethod (false));
             triggerUp.triggers.Add (pointerUp);
         }
 
         for (int i = 0; i < toggles.Length; i++) {
             EventTrigger triggerDown = toggles[i].gameObject.AddComponent<EventTrigger> ();
             var pointerDown = new EventTrigger.Entry ();
             pointerDown.eventID = EventTriggerType.PointerDown;
             pointerDown.callback.AddListener ((e) => MyInterfaceMethod (true));
             triggerDown.triggers.Add (pointerDown);
 
             EventTrigger triggerUp = toggles[i].gameObject.AddComponent<EventTrigger> ();
             var pointerUp = new EventTrigger.Entry ();
             pointerUp.eventID = EventTriggerType.PointerUp;
             pointerUp.callback.AddListener ((e) => MyInterfaceMethod (false));
             triggerUp.triggers.Add (pointerUp);
         }
     }
 
     public void MyInterfaceMethod (bool v) { //add parameters and interfaces as needed...
         IMyInterface[] thingsWithIMyInterface = findYourGameObjectHere.GetComponentsInChildren<IMyInterface> ();
 
         for (int i = 0; i < thingsWithMyInterface.Length; i++)
             thingsWithIMyInterface[i].MyInterfaceMethod (v);
     }
 }

The class is called "LockInputComponent" in my case because I'm using it to stop character functions while using UI. I'm aware that the original post is aged, so hopefully this doesn't "trigger" anyone. Pun intended. Not sorry.

Intended use is to place this at the top of your UI hierarchy and create interfaces for the things you want effected by it.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

209 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

changing script from key based function to GUI button for dice roll game 1 Answer

How to make Buttons communicate with UDP 2 Answers

Button onClick delegate with toggling method assignment 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges