Animating currently selected UI elements with multiple input methods

Hi there, I’m trying to use tweening (currently using DoTween: DOTween (HOTween v2) | Animation Tools | Unity Asset Store) to animate some UI elements in my game but I’m having issues when it comes to the buttons.

So what I want to do is have a UI where I have a selected button do its selected/highlight animation, in my case it scales up. When I select a different button or nothing, I want it to scale down.

Currently I’m achieving this with a script attached to my button prefab that uses the OnPointerEnter and OnPointerExit methods, and this works wonderfully.

The problem is I’m also trying to allow UI navigation with the keyboard arrow keys and a gamepad. For this I’m using the button scripts navigation features and the Unity Event System, and I can’t find an equivalent to the OnPointerEnter and OnPointerExit methods.

I could write a class that keeps track of what the EventSystem currently selected object is and then when it changes I would run those animations. I would have to also track the previously selected game object too to run the scale down.

Is there a better way of doing this? Mostly I would love to just have it all in 1 system so that if the button is selected by mouse, keyboard, or gamepad, run the selected animation.

You can probably have each object query the current EventSystem to ask if it has focus or not, then decide on what size it should be. That way no matter how something gets focus, it does the right thing.

Ha: I knew I had one of these lying around 27 of my projects… I cleaned one up, here you go:

1 Like

ISelectHandler and IDeselectHandler:

1 Like

Thanks for the replies! I was able to get it working using a combination of your suggestions.

Bit of a follow-up question though; I guess I was having trouble because I was worried about every button in the game accessing the Event System, but is doing something like EventSystem.current, dozens or hundreds of times, totally fine?

How many buttons do you have on at once?!

ALSO: DO NOT OPTIMIZE CODE JUST BECAUSE… If you don’t have a problem, DO NOT OPTIMIZE!

If you DO have a problem, always start by using the profiler:

Window → Analysis → Profiler

Failure to use the profiler means you’re just guessing, making a mess of your code for no good reason.

https://discussions.unity.com/t/841163/2

Notes on optimizing UnityEngine.UI setups:

https://discussions.unity.com/t/846847/2

If I had to guess, the bottleneck would NOT be accessing EventSystem.current but rather issuing scale change assignments when they are not in fact changing, which likely triggers a UI geometry rebuild. You could trivially update my script to not issue scale changes unless they are different than the previous frame, probably 3 lines of code total.

You can implement callbacks like Grozzler suggests above, but in my opinion I find those things ALWAYS have bizarre fragile side effects, such as failing when the user drags their finger off the edge of the screen, or the user turns off the device when his finger is in contact with the screen, or even simpler stuff like a scene change happens and the user’s finger was already down, flaky edge stuff like that. That’s why I favor a polled approach, but YMMV.

1 Like

I guess I was worried because my original idea was not completely unlike the code you provided except I was caching a reference to the EventSystem on Awake on each button, but you’re suggesting that each button should access EventSystem.current only when it needs to, so yeah, all of my other inactive buttons wouldn’t be doing that at the same time anyway.

Thanks again!

1 Like

I wanted to add an update to this in case someone finds this thread because even though the solution was already established, I found another solution not mentioned here that I personally didn’t know about.

I found two Unity built-in scripts that can be added to do exactly what I wanted:

  1. Selectable: This script adds a component to an object that is basically like a Button component without the OnClick functions. This allows for easy set up of the navigation system to use with keyboard and gamepad navigation.

  2. Event Trigger: This seems to be a component that has all the interface functions that were mentioned in this thread built-in. So you can choose to add PointerEnter, Select, Deselect, etc. without writing a script.

I’m not an expert, but these 2 components seem super easy to sue and seem to accomplish exactly what I wanted so I’m checking them out right now.

Now my script is only handling the tween animations when things get selected, or clicked, etc.