Menu with toggles with navigation and click events - why is that so difficult?

I want to create a menu where:
(1) every menu item has a text and a background. When focused, text is white and background appears. When not highlighted, text is black and background is invisible/transparent/disabled.
(2) Hovering over a menu item will focus it / set the toggle on
(3) Navigation with the arrow keys will focus different menu items and set their toggle on
(4) clicking enter on keyboard will press the menu item and will execute some events
(5) clicking with mouse on an item will execute some events (same as 4)

However:
(a) Should I use toggles together with buttons? should I use buttons and implement toggle functionality? should I use toggle and implement button functionality?
(b) I managed to use IPointerEnterHandler to change the ‘isOn’ property of a toggle, but IPointerClickHandler is never firing. I tried adding raycaster to camera, box collider to object, but it’s still not firing. I am using the Input System package if it matters.
(c) Arrow keys navigation doesn’t seem to work at all. On a toggle, the navigation property is set to automatic and pressing visualize looks correct - it shows up/down arrows between the different menu items. But pressing the arrow keys while the game is playing does nothing.

You seem to be using “focused”, “highlighted”, and “toggled on” interchangeably, but in standard uGUI abstractions those are all distinct things. I am confused about precisely how you are trying to map the standard abstractions to your desired functionality.

I don’t think Unity provides any callbacks for when a button or toggle is selected or highlighted, so if you want to run code when those things happen, you’ll either need to use polling (check every frame for changes) or somehow detect the preconditions that cause them to happen. You can check what object is currently selected via EventSystem.current.currentSelectedGameObject (in namespace UnityEngine.EventSystems).

(b) My best guess is that the click event is being “intercepted” by another object. Typically, if an object has NO handler for a particular UI event (such as pointerEnter, or click), and it receives such an event, it passes that event up the object hierarchy until it finds an object with a handler. But if an object has AT LEAST ONE handler for that specific event, then it will handle it “locally” and the parent will never hear about it. So, for example, if you have a child with a click handler, that can prevent you from detecting clicks that fall within that child.

But there’s lots of subtle errors that could theoretically cause you to fail to receive events. For instance, maybe you implemented the OnPointerClick method, but failed to update your class declaration to specify that you were implementing IPointerClickHandler, so Unity doesn’t know to call it.

Often it’s helpful to test out your script in a very simple scenario (one object, no unnecessary other components) and then add complications in gradually until you figure out which complication is breaking things.

(c) Remember that keyboard selection is NOT going to trigger a pointerEnter event, so if you are relying on that to set the toggle to “on”, then it’s not going to turn on even if keyboard navigation is working the way it’s supposed to.

Make sure that your Input is configured properly. The Event System in your scene has fields that define the specific inputs that it looks for to control keyboard navigation (by default: Horizontal, Vertical, Submit, and Cancel). Check your input manager to ensure that the keyboard buttons you are pressing are actually bound to those inputs.

If you select the Event System object while in playmode, it will display some debug information, including what object is currently “selected”. I’ve recently had some headaches where if NO object is currently “selected”, then keyboard navigation cannot seem to “get started” because it doesn’t know where to start from, so you might need to do something to make sure SOME object is selected in the first place. (For testing purposes: I usually press the mouse down on a button, drag the mouse away from the button while still holding down, and then release; this results in the button being selected but not clicked.)

Again, you might find it helpful to test in a simpler environment to make sure the basics are working before you test in your weird custom set-up.

First I have to thank you for the detailed response!

Now to the fun part:

  • I never mentioned any callbacks regarding those events. However, I did them using animations. Both button and toggles have transition property, which you can set to animation, and in the animation you can set the properties.

(b) I’m not sure I fully understand, but is there a way to know who intercepted that event, rather than search for it? since I didn’t write any other click handlers, if it is intercepted by something else, it is by one of the unity classes, which I have no idea how to find out…

(c) I was actually relying on the keys to change the selected object. The one that is shown by the Event System object when playing, as debug info, like you suggested. It never did though.

(a) Keep in mind that being “highlighted” is still different from being “selected”. For instance, pointing the mouse at a button will (by default) cause it to become highlighted, but it won’t become selected unless you press down.

(b) Check the Event System debug info for “pointerEnter” and “pointerPress”.

(c) I can only recommend you start working your way through the debugging suggestions in my previous post.