onMenu behavior with Menu2/CustomMenu

Good morning,

Is there a way to implement onMenu behavior within a CustomMenu?

The Menu2InputDelegate doesn't appear to provide an onMenu method. I tried implementing it manually, but it doesn't seem to be triggered.

Is there a known workaround or recommended approach for this scenario?

Top Replies

All Replies

  • Yes, I already realized that onFooter() wasn’t what I was looking for. I'm currently working on the implementation, and it turns out onNextPage() does the trick. I haven’t fully fleshed it out yet, but it’s looking promising.

    I completely understand your point about this kind of UI behavior - to be honest, I’ve always found it a bit confusing on my own watch as well.

    That said, I think it makes sense for my app. The main menu is generated from a JSON payload provided by the server, and it's updated dynamically as the app continuously polls for changes. So from both a programmatic and user experience perspective, it feels cleaner to separate the settings from the main menu.

    Ideally, I’d still prefer to open the settings via onMenu(), but having a secondary menu "below" the root is definitely a better approach than embedding settings directly into the main menu.

  • I find it odd that Menu2 does not have a member variable or function that returns the number of its items.

    So, when I want to set the focus on the last item, I basically have to keep track of the number of items.

  • Yeah onNextPage() / onPreviousPage() make more sense than onWrap(), given that you want to emulate the native behaviour of opening a new menu / returning to previous menu on *either* button press or swipe (in the appropriate place / direction).

    I completely understand your point about this kind of UI behavior - to be honest, I’ve always found it a bit confusing on my own watch as well.

    Yeah I think Garmin agrees too.

    It's pretty funny that Garmin introduced this behaviour in an apparent attempt to simplify previous behaviour, only to return to the previous behaviour after all

    So from both a programmatic and user experience perspective, it feels cleaner to separate the settings from the main menu.

    But my point is that if you open a new menu when the user scrolls down at the bottom of the first menu, to the user the two menus will seem like a single menu anyway (despite the fact that there may be a footer at the first menu and that there will be a title for the second menu).

    That's the behaviour that Garmin introduced a few years back and recently reverted with Fenix 8.

    Fenix 8 no longers opens settings when you scroll down from another menu; it just has a separate menu item - "Watch Settings" - which opens a sub menu in the normal way.

  • to the user the two menus will seem like a single menu anyway (despite the fact that there may be a footer at the first menu and that there will be a title for the second menu).

    Yes, I agree - it feels more like a single menu with a separator than two distinct menus. The wrapping behavior reinforces that: scrolling past the end of the settings loops back to the first main menu item.

    For now, I’m happy with how it turned out. That said, depending on user feedback, I might eventually turn the settings into a regular menu item. To distinguish it visually, I could style it with a grey tone to set it apart from the others.

  • Unfortunately, the behavior on the actual watch didn’t match expectations.

    It looks like there’s a bug in the Menu2InputDelegate implementation of onWrap(). Even when returning false, the menu still wraps around.

    In my case, the settings menu uses Menu2. When I switch views inside onWrap(), onPreviousPage(), or onNextPage(), the display first jumps to the opposite end of the menu before transitioning views. This behavior doesn’t show up in the simulator.

    Interestingly, CustomMenu doesn’t have this issue - view switching works smoothly there.

    So now I’m left with two options: switch the settings menu to CustomMenu (and lose the convenience of built-in MenuItem implementations), or implement the settings as its own menu item in the main menu after all.

    It’s a bit frustrating - debugging around SDK bugs continues to be a time sink.

  • It looks like there’s a bug in the Menu2InputDelegate implementation of onWrap(). Even when returning false, the menu still wraps around.

    You mean when returning true? In input/behaviour delegates, returning true means you handled the event, so the default behaviour should be suppressed. Returning false means you didn't handle the event, so the default behaviour should be applied.

  • It’s a bit frustrating - debugging around SDK bugs continues to be a time sink.

    Welcome to Connect IQ!

  • You mean when returning true?

    It seems onWrap() behaves a bit differently than other delegate functions. According to the documentation:

    If this method returns false, the list will not wrap to the opposite end. If this method is not overridden, it will return true and allow the menu to wrap.

    In the simulator, this mostly works as described - returning true enables wrapping, and returning false disables it. That said, wrapping when navigating up from the first element appears broken in the simulator regardless of the delegate implementation.

    On the real watch, the behavior is more confusing. I had onNextPage() and onPreviousPage() push and pop views, but the menu still jumps to the opposite end before switching views - even when onWrap() returns false.

    I'll run more tests to better understand what's happening on the device.

  • I tested again with a minimal delegate, and on the watch, onWrap() simply doesn’t work as documented. Regardless of whether I return true or false, Menu2 always wraps.

    class SettingsMenuDelegate extends Menu2InputDelegate {
        public function initialize() {
            Menu2InputDelegate.initialize();
        }

        public function onWrap( key as WatchUi.Key ) as Lang.Boolean {
            return false;
        }
    }
  • I’ve submitted a bug report:
    https://forums.garmin.com/developer/connect-iq/i/bug-reports/menu2inputdelegate-onwrap-returning-false-does-not-prevent-wrapping-on-a-real-device

    As a workaround, I’ve switched the settings menu from Menu2 to CustomMenu. With CustomMenu, the behavior is closer to what I need. There’s no onWrap() method, but by overriding onNextPage() and onPreviousPage(), I can effectively disable wrapping.

    This is the first significant bug I’ve encountered while developing my new app. Significant in the sense that the workaround is both time-consuming and results in a less polished user experience.