Do we have access to the 'dots' on left of the screen when there are multiple pages to scroll through?

Hi, in Garmin's native apps, I sometime sees dots on the left of the screen that tells me which pages I'm on (I don't know what they are called). Is this feature available to CIQ too or do we need to built it ourselves if we want something similar?

  • If you want something like that in your CIQ apps, then you would have to build it yourself 

  • They're called page indicators and Garmin added support for defining a "view loop" with page indicators in CIQ 3.4:

    https://developer.garmin.com/connect-iq/api-docs/Toybox/WatchUi/ViewLoop.html 

    https://developer.garmin.com/connect-iq/personality-library/page-loops/ 

    I vaguely remember hearing from one dev that the implementation isn't great tho

  • Hmm, I was looking at the PrimateViewLoop sample and from what I gather, I would need to reread all the storage and member variables as it starts a new view each time. This would not be very effective for my usage. I might follow what sabeard said I do it myself. Plus it's for 3.4 and above while I do support quite a bunch of devices from the 3.2 era.

  • This is the code I ended going with:

    Sorry, I can't post it in 'source code' format as I get "You've been blocked" when I try that way and in plain text, I also get an error :-(

    mShowPageMarker is set when I switch to another panel and since the update runs every five seconds, the markers disappears after that time has elapsed. 

    mCtrX and mCtrY is the center of the screen.

    MAX_SCREEN is the number of 'screens' (ie, pages) that can be displayed (7 in total).

    mViewScreen is the panel currently being displayed (which would be 0 in the screenshot below)

    mPanelSize is the numbers of panels the user has selected to be displayed.

    So it ends up looking like this

  • Well...nothing prevents you from returning the exact same view for every page in your view loop.

    e.g. In your ViewLoopFactory:

    var m_singleView; // assume this is initialized once
    var m_singleDelegate; // assume this is initialized once
    function getPage(page as Lang.Number) {
        m_singleView.setPage(page);
        return [m_singleView, m_singleDelegate];
    }

    On the flip side, even if you have a distinct view for each page, nothing forces your app to load common state when each view is initialized. You could load it once and pass it around to each view. (i.e. Have a separate class for reading, writing and persisting common app state.)

    Seems to me that the advantage of using ViewLoop is that hopefully it will conform to the standard user experience for the given watch, in both appearance and behaviour (especially when it comes to handling input).

    For example, I've used apps where swiping up actually does the same thing as the UP button - it scrolls up to the page which is "above" the current one. This goes against the way every touch UI has worked for 10+ years, with regards to paging and scrolling (swipes are supposed to have the opposite effect as "arrow keys" or mouse scroll wheels, because when you swipe, you're moving the content itself, but when you use arrow keys or scroll wheels, you're moving a cursor through the content.)

    I've also used apps where pressing START cycles down through a vertical list. (No native app works like this on my 5-button + touch FR955 - vertical lists are navigated using the UP/DOWN buttons or down/up swipes, and if START is ever used to change pages, it only ever applies to a horizontal list of pages that's subordinate to the current page in a vertical list.)

    In the end, it's up to you. Personally I wouldn't want to reinvent the wheel if Garmin has something that works. (Menu2 is a great example. The original Menu was very basic and had a ton of issues, and it wasn't surprising that some devs implemented their own custom view. But once Menu2 came out - and it was guaranteed to have the same look and feel as native menus - there was very little reason to use a custom menu component.)

  • Hi, I gave it a try and I had to move stuff out of the onHide, onLayout and onShow functions because even if the view class itself hasn't changed, they are still called when switching view through the ViewLoop, these functions are where I put stuff that should be kept between all the different 'views' this app has. Now what was in onLayout (except if it required the dc variable which fortunately, was just the best font selection) and onShow are into the view's Initialize  function. What was in onHide was moved to onStop if it was called for the main view (and not the background or glance view). Except there I couldn't shutdown the timer I've set in the View Initialize function but since I'm shutting down anyway, I'm assuming it would be auto destroyed by the app shutting down.

    Had to create some weird logic to let the original swipe up/down button up/down work when I'm in a specific view as they are used to zoom/pan a history graph (after using the Start button/touch screen to activate the Zoom or Pan mode).

    It's now running on my Fenix 7S Pro to see if it works similar to the simulator.

    Thanks

  • So I have a question regarding the standard used in the ViewLoop logic. In the Primate example, the onNextView has DIRECTION_PREVIOUS and the onPreviousView has DIRECTION_NEXT. What? Why did they do that? Shouldn't it be the other way around? Next has NEXT and Previous has PREVIOUS?

    One place I saw this page indicator being used intrinsically is with the watch face selection in Settings. Its use is reversed compared to the sample. Also, the watch face selection starts at the bottom while the sample has it starting at the top (index 0). I changed my code to make it similar to the watch face indicator, which seems more intuitive.

    So, is there a consensus on its use? Garmin's sample seems to contradict what the device does.

  • In the Primate example, the onNextView has DIRECTION_PREVIOUS and the onPreviousView has DIRECTION_NEXT. What? Why did they do that? Shouldn't it be the other way around? Next has NEXT and Previous has PREVIOUS?

    Sounds like a bug to me. Sounds like what you're saying is right, but to be double-check, I would want to be sure to pick the usage that ensures:

    - UP button moves to the view "above"

    - DOWN button moves to the view "below"

    - UP swipe moves to the view "below"

    - DOWN swipe moves to the view "above"

    IOW, the buttons should move a "cursor" through the content (like all old-school scrolling on non-touch interfaces), while swipes should move the content itself (e.g. to navigate up through the content, you have to have move the content itself down.)

    Also, the watch face selection starts at the bottom while the sample has it starting at the top (index 0). I changed my code to make it similar to the watch face indicator, which seems more intuitive.

    I think this is arbitrary and not even Garmin is consistent here.

    For example, the activity page loop starts at top and not the bottom. Menus generally start at the top, too (unless it's the kind of menu that starts at the value which reflects the current value of a setting)

    Also, on my watch, watch face selection start with the current watch face (which can be anywhere in the list), and all the native watch faces come first, followed by the CIQ watch faces.

  • Maybe it's not a bug, but a different way of looking at things. Up/down prev/next thing always confused me, not only here. And I'm pretty sure it's not only me. It's based on a way of looking at what's going up. Think about the difference between how scrolling a website in the browser with the mouse scroll wheel (or touchpad) between a Mac and any other OS. It can be very confusing when you're used to the other way, and it can be very natural when you're used to it.

    In terms of the up/down buttons in a Garmin device, arguably both make sense (let's put the default Garmin behavior aside for a moment): When I look at a list and I click the Up button:

    a) the list moves UP

    b) the window I see moved UP over the list

    To make things more confusing some devices have left/right buttons, that are also mapped to prev/next

  • I think OP is saying that the Primate sample works differently (as far as input/scrolling goes) from the native Garmin UI, not that the Garmin UI is different from other UIs. They are also saying it makes no sense for the onNextView() handler to ask the view loop to go in DIRECTION_PREV and vice versa.

    As I'll argue below, the Garmin UI is actually the same as other UIs, when you compare the Garmin UP/DOWN buttons to computer arrow keys, and Garmin touch swipe to swipes on any other touchscreen.

    Having said that, I didn't actually try the sample until now. Now that I have tried it on the simulator, I think it works properly on an FR935 (5-button watch without a touchscreen), but improperly on an FR955 (5-button watch with touchscreen)

    - On FR935, the view loop is horizontal. The DOWN button takes you to the "next" element on the right, and the UP button takes you to the "previous" element on the left. I think this is logical (if not necessarily intuitive) because when you are moving through a vertical list, UP is previous and DOWN is next; it's perfectly analogous to the horizontal list behaviour. This is fine to me, except it would be more intuitive if the list scrolling axis was vertical. 

    - On FR955, the view loop is vertical. The DOWN button moves you up through the list and the UP button moves you down. Swiping up moves up through the list and swiping down moves down. This is the exact opposite of how the native Garmin UI works (there are many examples of this - activity data pages, menus, watchface / glance list, watchface selection UI). This is also the opposite of how touchscreens from every vendor works. If you take the Garmin UP/DOWN buttons to be analogous to UP/DOWN arrow keys on a computer, it also works the opposite way of how arrow keys work.

    [1/x]