Data Field onTap() behavior on Edge Devices

Hi!

I created a little data field that shows distance and toggles between units (miles/Km) when you tap on the data field.

Works as designed on the simulator.

However.... 

In the real world when you tap the data field (say on an Edge 1030), the app navigation pops up (home, next page, prev page).  Tapping again clears that, and the data field toggles to it's new setting.

Any way to disable this navigation screen from popping up when this particular data field is tapped?

Thanks for any guidance.


T

  • I had the same issue.  That is the way the garmin normally works. so you are missing something.  I will try to post some code.

  • This should be in a Delegate.mc  file

    using Toybox.WatchUi;

    class ElevationDelegate extends WatchUi.BehaviorDelegate {

        function initialize() {

        

            BehaviorDelegate.initialize();

            var deviceSettings = System.getDeviceSettings();

      

        }

        function onTap(evt) {

           

            increment = true;

            playSound = true;

            

            return true;

        

        }

    }

  • This should be in your app.ms file - My app is called Elevation.

    using Toybox.Application;

    class ElevationApp extends Application.AppBase {

        function initialize() {

            AppBase.initialize();

        }

    function onSettingsChanged() {

    getSettings = true;

    return [ new ElevationView() ];

    }

        // onStart() is called on application start up

        function onStart(state) {

        }

        // onStop() is called when your application is exiting

        function onStop(state) {

        }

        //! Return the initial view of your application here

        function getInitialView() {

            return [ new ElevationView(), new ElevationDelegate() ];

        }

    }

  • Awesome, thanks, I'll give it a try!

  • I changed my code to look like yours, but the home screen still pops up after touching the data field....

    Here's my code, in case you have a moment to look at what I may be doing wrong....

    ================

    view.mc

    using Toybox.WatchUi as Ui;

    using Toybox.System as Sys;

    using Toybox.Time as Time;

    using Toybox.Lang as Lang;

    var GlobalTouched = 0;

    class StatuteMetricElapsedDistanceCarouselView extends Ui.DataField {

        hidden var mValue;

        const METERS_TO_MILES = 0.000621371;

        const METERS_TO_KILOMETERS = 0.001;

       const CONVERSION_FACTOR = [METERS_TO_KILOMETERS, METERS_TO_MILES];

        const MILES_OR_KILOMETERS = ["Dist(K)","Dist(M)"];

        var label = MILES_OR_KILOMETERS[0];

        hidden var format_choice = "%.1f";

        var counter;

        function initialize() {

            counter = 0;

            DataField.initialize();

            mValue = 0.0f;    

            }

        // Set your layout here. Anytime the size of obscurity of

        // the draw context is changed this will be called.

        function onLayout(dc) {

            var obscurityFlags = DataField.getObscurityFlags();

            // Top left quadrant so we'll use the top left layout

            if (obscurityFlags == (OBSCURE_TOP | OBSCURE_LEFT)) {

                View.setLayout(Rez.Layouts.TopLeftLayout(dc));

            // Top right quadrant so we'll use the top right layout

            } else if (obscurityFlags == (OBSCURE_TOP | OBSCURE_RIGHT)) {

                View.setLayout(Rez.Layouts.TopRightLayout(dc));

            // Bottom left quadrant so we'll use the bottom left layout

            } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_LEFT)) {

                View.setLayout(Rez.Layouts.BottomLeftLayout(dc));

            // Bottom right quadrant so we'll use the bottom right layout

            } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_RIGHT)) {

                View.setLayout(Rez.Layouts.BottomRightLayout(dc));

            // Use the generic, centered layout

            } else {

                View.setLayout(Rez.Layouts.MainLayout(dc));

                var labelView = View.findDrawableById("label");

                labelView.locY = labelView.locY - 30;

                var valueView = View.findDrawableById("value");

                valueView.locY = valueView.locY + 7;

            }

            View.findDrawableById("label").setText(Rez.Strings.label);

            return true;

        }

        // The given info object contains all the current workout information.

        // Calculate a value and save it locally in this method.

        // Note that compute() and onUpdate() are asynchronous, and there is no

        // guarantee that compute() will be called before onUpdate().

        function compute(info) {

            // See Activity.Info in the documentation for available information.

            var distance = 0.0f;

            //Cycle between kilometers and miles to be displayed

            if(info.elapsedDistance != null) { 

          //convert the elapsed distance from meters to Miles or Kilometers

          distance = info.elapsedDistance*CONVERSION_FACTOR[counter];

            

            //format the display so 3 digits show up: xxx, xx.x or x.xx

            format_choice = "%.1f"; // default - 10 < distance < 100 - use one decimal place on display

            if(distance < 10.0) {

            format_choice = "%.2f"; // distance < 10 - use 2 decimal places

            }

            if(distance >= 100.0) {

            format_choice = "%.0f"; // distance > 100 use no decimals

            }

    //calculate the value to be displayed xx.x [M|K]

           

           }

           label = MILES_OR_KILOMETERS[counter];

            mValue = distance;

           if (GlobalTouched == 1) {

           counter ^= 1; // flip between 0 and 1 using XOR

           GlobalTouched = 0;

            }

        }

        // Display the value you computed here. This will be called

        // once a second when the data field is visible.

        function onUpdate(dc) {

            // Set the background color

            View.findDrawableById("Background").setColor(getBackgroundColor());

            // Set the foreground color and value

            var value = View.findDrawableById("value");

            if (getBackgroundColor() == Graphics.COLOR_BLACK) {

                value.setColor(Graphics.COLOR_WHITE);

            } else {

                value.setColor(Graphics.COLOR_BLACK);

            }

            value.setText(mValue.format(format_choice));

            View.findDrawableById("label").setText(label);

            // Call parent's onUpdate(dc) to redraw the layout

            View.onUpdate(dc);

        }

    }

    // class StatuteMetricElapsedDistanceCarouselDelegate extends Ui.InputDelegate {

    // Handle touch events

    class StatuteMetricElapsedDistanceCarouselDelegate extends Ui.BehaviorDelegate {

    function initialize() {

      BehaviorDelegate.initialize();

      var deviceSettings = System.getDeviceSettings();

      }

    // Handle touch events

    function onTap(evt) {

    // Process the touch event

      GlobalTouched = 1;

      }

    }

    =========

    app.mc

    using Toybox.Application;

    class StatuteMetricElapsedDistanceCarouselApp extends Application.AppBase {

        function initialize() {

            AppBase.initialize();

        }

    function onSettingsChanged() {

    // getSettings = true;

    return [new StatuteMetricElapsedDistanceCarouselView()];

    }

        // onStart() is called on application start up

        function onStart(state) {

        }

        // onStop() is called when your application is exiting

        function onStop(state) {

        }

        //! Return the initial view of your application here

        function getInitialView() {

            return [ new StatuteMetricElapsedDistanceCarouselView(), new StatuteMetricElapsedDistanceCarouselDelegate() ];

        }

    }

  • Is your last section in a Delegate.mc?

    using Toybox.WatchUi;

    class ElevationDelegate extends WatchUi.BehaviorDelegate {

        function initialize() {

        

            BehaviorDelegate.initialize();

            var deviceSettings = System.getDeviceSettings();

      

        }

        function onTap(evt) {

           

            increment = true;

            playSound = true;

            

            return true;

        

        }

    }

  • Sorry the last section of the view before the app.mc

  • First, thanks again!

    Here's how I have it broken up in the project, with file names:

    SMEView.mc

    using Toybox.WatchUi as Ui;

    using Toybox.System as Sys;

    using Toybox.Time as Time;

    using Toybox.Lang as Lang;

    var GlobalTouched = 0;

    class StatuteMetricElapsedDistanceCarouselView extends Ui.DataField {

        hidden var mValue;

        const METERS_TO_MILES = 0.000621371;

        const METERS_TO_KILOMETERS = 0.001;

       const CONVERSION_FACTOR = [METERS_TO_KILOMETERS, METERS_TO_MILES];

        const MILES_OR_KILOMETERS = ["Dist(K)","Dist(M)"];

        var label = MILES_OR_KILOMETERS[0];

        hidden var format_choice = "%.1f";

        var counter;

        function initialize() {

            counter = 0;

            DataField.initialize();

            mValue = 0.0f;    

            }

        // Set your layout here. Anytime the size of obscurity of

        // the draw context is changed this will be called.

        function onLayout(dc) {

            var obscurityFlags = DataField.getObscurityFlags();

            // Top left quadrant so we'll use the top left layout

            if (obscurityFlags == (OBSCURE_TOP | OBSCURE_LEFT)) {

                View.setLayout(Rez.Layouts.TopLeftLayout(dc));

            // Top right quadrant so we'll use the top right layout

            } else if (obscurityFlags == (OBSCURE_TOP | OBSCURE_RIGHT)) {

                View.setLayout(Rez.Layouts.TopRightLayout(dc));

            // Bottom left quadrant so we'll use the bottom left layout

            } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_LEFT)) {

                View.setLayout(Rez.Layouts.BottomLeftLayout(dc));

            // Bottom right quadrant so we'll use the bottom right layout

            } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_RIGHT)) {

                View.setLayout(Rez.Layouts.BottomRightLayout(dc));

            // Use the generic, centered layout

            } else {

                View.setLayout(Rez.Layouts.MainLayout(dc));

                var labelView = View.findDrawableById("label");

                labelView.locY = labelView.locY - 30;

                var valueView = View.findDrawableById("value");

                valueView.locY = valueView.locY + 7;

            }

            View.findDrawableById("label").setText(Rez.Strings.label);

            return true;

        }

        // The given info object contains all the current workout information.

        // Calculate a value and save it locally in this method.

        // Note that compute() and onUpdate() are asynchronous, and there is no

        // guarantee that compute() will be called before onUpdate().

        function compute(info) {

            // See Activity.Info in the documentation for available information.

            var distance = 0.0f;

            //Cycle between kilometers and miles to be displayed

            if(info.elapsedDistance != null) { 

          //convert the elapsed distance from meters to Miles or Kilometers

          distance = info.elapsedDistance*CONVERSION_FACTOR[counter];

            

            //format the display so 3 digits show up: xxx, xx.x or x.xx

            format_choice = "%.1f"; // default - 10 < distance < 100 - use one decimal place on display

            if(distance < 10.0) {

            format_choice = "%.2f"; // distance < 10 - use 2 decimal places

            }

            if(distance >= 100.0) {

            format_choice = "%.0f"; // distance > 100 use no decimals

            }

    //calculate the value to be displayed xx.x [M|K]

           

           }

           label = MILES_OR_KILOMETERS[counter];

            mValue = distance;

           if (GlobalTouched == 1) {

           counter ^= 1; // flip between 0 and 1 using XOR

           GlobalTouched = 0;

            }

        }

        // Display the value you computed here. This will be called

        // once a second when the data field is visible.

        function onUpdate(dc) {

            // Set the background color

            View.findDrawableById("Background").setColor(getBackgroundColor());

            // Set the foreground color and value

            var value = View.findDrawableById("value");

            if (getBackgroundColor() == Graphics.COLOR_BLACK) {

                value.setColor(Graphics.COLOR_WHITE);

            } else {

                value.setColor(Graphics.COLOR_BLACK);

            }

            value.setText(mValue.format(format_choice));

            View.findDrawableById("label").setText(label);

            // Call parent's onUpdate(dc) to redraw the layout

            View.onUpdate(dc);

        }

    }

    ================

    SMEApp.mc

    using Toybox.Application;

    class StatuteMetricElapsedDistanceCarouselApp extends Application.AppBase {

        function initialize() {

            AppBase.initialize();

        }

    function onSettingsChanged() {

    // getSettings = true;

    return [new StatuteMetricElapsedDistanceCarouselView()];

    }

        // onStart() is called on application start up

        function onStart(state) {

        }

        // onStop() is called when your application is exiting

        function onStop(state) {

        }

        //! Return the initial view of your application here

        function getInitialView() {

            return [ new StatuteMetricElapsedDistanceCarouselView(), new StatuteMetricElapsedDistanceCarouselDelegate() ];

        }

    }

    ====================

    SMEBackground.mc

    using Toybox.WatchUi;

    using Toybox.Application;

    using Toybox.Graphics;

    class Background extends WatchUi.Drawable {

        hidden var mColor;

        function initialize() {

            var dictionary = {

                :identifier => "Background"

            };

            Drawable.initialize(dictionary);

        }

        function setColor(color) {

            mColor = color;

        }

        function draw(dc) {

            dc.setColor(Graphics.COLOR_TRANSPARENT, mColor);

            dc.clear();

        }

    }

    =================

    SMEDelegate.mc

    using Toybox.WatchUi as Ui;
    using Toybox.System as Sys;
    using Toybox.Time as Time;
    using Toybox.Lang as Lang;

    // class StatuteMetricElapsedDistanceCarouselDelegate extends Ui.InputDelegate {
    // Handle touch events
    // function onTap(evt) {
    // Process the touch event
    // GlobalTouched = 1;
    // }
    //}

    class StatuteMetricElapsedDistanceCarouselDelegate extends Ui.BehaviorDelegate {

    function initialize() {
    BehaviorDelegate.initialize();
    var deviceSettings = System.getDeviceSettings();
    }

    // Handle touch events
    function onTap(evt) {
    // Process the touch event
    GlobalTouched = 1;
    }
    }

  • One odd thing is that when I try to open the SMEDelegate.mc in eclipse, I get "Failed to create the part's controls"

    But it builds fine and runs fine, except for the home menu popping up

  • The key is that onTap(evt) has to return true to say you handled the event in your code.

    Have a look at the example of or the api documentation:

    developer.garmin.com/.../InputDelegate.html