简体   繁体   中英

how to enable ionic multi-touch events

I 'm developing a simple ionic app, and part of the app requires you to press two buttons at once. I've built this logic like so:

<!--yT stands for yourThumb, pT stands for partnersThumb -->


<a class="icon ion-qr-scanner lg-txt" on-hold="Global.thumbHoldManager('yT',true)" on-release="Global.thumbHoldManager('yT',false, true)"></a>

<a class="icon ion-qr-scanner lg-txt" on-hold="Global.thumbHoldManager('pT',true)" on-release="Global.thumbHoldManager('pT',false, true)"></a>

I have a method on my controller which handles this event using a service I 've created

var globalCtrl = function (clickHandler, $timeout) {
  var self = this;
  this.clickHandler = clickHandler;
  this.timeout = $timeout;
  this.readyState = clickHandler.ready;
  this.showInstruction = false;

  clickHandler.watchForReady();

};

globalCtrl.prototype.thumbHoldManager = function(which, what, up) {
    this.clickHandler.setClickState(which, what);
    var self = this;

    if (up) {
        this.clickHandler.stopWatching();
    }

    if (!this.readyState) {
        this.instruction = "Hold both thumbs in place to scan"
        if (!this.showInstruction) {
                this.showInstruction = true;
                self.timeout(function() {
                self.showInstruction = false;
            }, 5000)
        }
    }
};

globalCtrl.$inject = ['clickHandler', '$timeout'];

The service clickHandler exposes an api to a private object whose job it is to track when a button is pressed, and when both buttons are pressed to navigate to a new url.

.factory('clickHandler', [
    '$interval',
    '$rootScope',
    '$location',
    function($interval, $rootScope, $location) {

    // Service logic
    // ...

        var clickState = {
            yT: false,
            pT: false,
            ready: false,
            watching: false,
            watcher: false
        };

    // Public API here

        return {
            setClickState: function(which, what) {
                clickState[which] = what;
            },

            getClickState: function(which) {
                return clickState[which]
            },

            getReadyState: function() {
                return ((clickState.yT) && (clickState.pT));
            },

            watchForReady: function() {
                var self = this;
                clickState.watching = $interval(function() {
                    clickState.ready = self.getReadyState();
                },50);

                clickState.watcher = $rootScope.$watch(function() {
                    return clickState.ready
                }, function redirect(newValue) {
                    if (newValue) {
                        self.stopWatching();
                        $location.path('/scan');
                    }
                })
            },

            stopWatching: function() {
                if (clickState.watching) {
                    $interval.cancel(clickState.watching);
                    clickState.watcher();
                    clickState.watching = false;
                    clickState.watcher = false;

                }
            }

        };
    }
])

I don't get any errors with this code, everything works as it should, the watcher gets registered on the hold event and unregistered on the release event. But no matter what I do, I cannot seem to get my phone to detect a press on both buttons. It's always one or the other and I don't know why. I can't test this in the browser or the emulator since multi-touch is not supported and I don't have a multi-touch trackpad if it were.

Here's how I implemented my own directive and service to do this:

.factory('clickHandler', ['$interval', '$rootScope', '$location', '$document', function ($interval, $rootScope, $location, $document) {
// Service logic
// ...

$document = $document[0];



var
  touchStart,
  touchEnd;

touchStart = ('ontouchstart' in $document.documentElement) ? 'touchstart' : 'mousedown';
touchEnd = ('ontouchend' in $document.documentElement) ? 'touchend' : 'mouseup';

var clickState = {
  yT:         false,
  pT:         false,
  ready:      false,
  watching:   false,
  watcher:    false,
  startEvent: touchStart,
  endEvent:   touchEnd
};

// Public API here
return {
  setClickState: function (which, what) {
    clickState[which] = what;
  },

  getClickState: function (which) {
    return clickState[which]
  },

  getReadyState: function () {
    return ( (clickState.yT) && (clickState.pT) );
  },

  watchForReady: function () {
    var self = this;

    //prevent multiple redundant watchers

    if (clickState.watching) {
      return;
    }

    clickState.watching = $interval(function () {
      clickState.ready = self.getReadyState();
    }, 50);

    clickState.watcher = $rootScope.$watch(function () {
      return clickState.ready
    }, function redirect(newValue) {
      if (newValue) {
        self.stopWatching();
        $location.path('/scan');
      }
    })
  },

  stopWatching: function () {
    if (clickState.watching) {
      $interval.cancel(clickState.watching);
      clickState.watcher();
      clickState.watching = false;
      clickState.watcher = false;

    }
  },

  getTouchEvents: function () {
    return {
      start: clickState.startEvent,
      end:   clickState.endEvent
    }
  }




  };
}])

.directive('simultaneousTouch', ['clickHandler', '$document', function (clickHandler) {
  return {
    restrict: 'A',
    link:     function (scope, elem, attr) {
      var touchEvents = clickHandler.getTouchEvents();

      elem.on(touchEvents.start, function () {

        clickHandler.watchForReady();
        clickHandler.setClickState(attr.simultaneousTouch, true);
      });

      elem.on(touchEvents.end, function () {
        clickHandler.stopWatching();
        clickHandler.setClickState(attr.simultaneousTouch, false);
      })
    }
  }
}]);

Crossposting stankugo's answer from the ionic forums for the sake of reference. The simple solution below is entirely his idea, I've just done a little cleanup.

angular.module('xxxx').directive('multitouch', function () {
    return function(scope, element, attr) {
        element.on('touchstart', function() {
            scope.$apply(function() {
                scope.$eval(attr.multitouch);
            });
        });
    };
});

Use like:

<div multitouch="handler()"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM