Last active
March 23, 2021 13:17
-
-
Save nixta/ed31857dc1cd8abaebd6e7eacaa8b26f to your computer and use it in GitHub Desktop.
A Google-Maps like single-finger zoom gesture for the ArcGIS Runtime SDK for iOS. Awesome idea, Google Maps team! πππ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AGSSingleFingerZoomGestureRecognizer.swift | |
// | |
// Created by Nicholas Furness on 6/17/16. | |
// Copyright Β© 2016 Esri. All rights reserved. | |
// | |
import Foundation | |
import ArcGIS | |
import UIKit.UIGestureRecognizerSubclass | |
enum AGSSingleFingerZoomMode { | |
case Google | |
case UpOutDownIn(centeredOnTap:Bool) | |
case UpInDownOut(centeredOnTap:Bool) | |
func translateScaleFactor(factor:Double) -> Double { | |
switch self { | |
case .Google, .UpOutDownIn: | |
return -factor | |
case .UpInDownOut: | |
return factor | |
} | |
} | |
} | |
class AGSSingleFingerZoomGestureRecognizer : UIGestureRecognizer { | |
var scalePower:Double = 5.0 | |
var zoomMode:AGSSingleFingerZoomMode = .UpOutDownIn(centeredOnTap: true) | |
private var anchorPoint:CGPoint? | |
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent) { | |
super.touchesBegan(touches, withEvent: event) | |
guard let mapView = self.view as? AGSMapView else { | |
print("You should only apply \(self.dynamicType) to an AGSMapView!") | |
self.state = .Failed | |
return | |
} | |
guard touches.count == 1 else { | |
// Single finger only | |
self.state = .Cancelled | |
return | |
} | |
if let tap = touches.first { | |
guard tap.tapCount <= 2 else { | |
// Second tap becomes the drag, so no more than 2 taps allowed | |
self.state = .Cancelled | |
return | |
} | |
if tap.tapCount == 2 { | |
// We're doing the drag, so remember where we tapped | |
self.anchorPoint = self.locationInView(mapView) | |
self.state = .Began | |
} | |
} | |
} | |
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent) { | |
super.touchesMoved(touches, withEvent: event) | |
guard self.state != .Failed else { | |
// Apple recommend you check this. | |
return | |
} | |
guard [.Began, .Changed].contains(self.state) else { | |
// Only continue if we've determined the gesture is happening, continue. | |
return | |
} | |
guard let mapView = self.view as? AGSMapView else { | |
print("You should only apply \(self.dynamicType) to an AGSMapView!") | |
self.state = .Failed | |
return | |
} | |
guard touches.count == 1 else { | |
// Only 1 finger | |
self.state = .Cancelled | |
return | |
} | |
if let touch = touches.first { | |
let prevLoc = touch.previousLocationInView(mapView) | |
let thisLoc = touch.locationInView(mapView) | |
if CGPointEqualToPoint(prevLoc, thisLoc) { | |
return | |
} | |
let diff = Double(thisLoc.y - prevLoc.y) | |
// Scale ratio is determined by taking a proportion of the screen height we've dragged, and raising by a power. | |
let scaleRatio = pow(1 + (self.zoomMode.translateScaleFactor(diff) / Double(mapView.frame.height)), self.scalePower) | |
switch self.zoomMode { | |
case .UpInDownOut(true), .UpOutDownIn(true): | |
// Zoom in/out around the tap point | |
mapView.zoomWithFactor(scaleRatio, atAnchorPoint: self.anchorPoint!, animated: false) | |
default: | |
// Zoom in/out around the center of the map view | |
let newScale = mapView.mapScale * scaleRatio | |
mapView.zoomToScale(newScale, animated: false) | |
} | |
} | |
} | |
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent) { | |
super.touchesEnded(touches, withEvent: event) | |
self.state = .Ended | |
} | |
override func reset() { | |
self.anchorPoint = nil | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ViewController.swift | |
// DoubleTapZoom | |
// | |
// Created by Nicholas Furness on 6/17/16. | |
// Copyright Β© 2016 Esri. All rights reserved. | |
// | |
import UIKit | |
import ArcGIS | |
class ViewController: UIViewController { | |
@IBOutlet weak var mapView: AGSMapView! | |
let singleFingerZoomGesture = AGSSingleFingerZoomGestureRecognizer() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// Do any additional setup after loading the view, typically from a nib. | |
let basemap = AGSTiledMapServiceLayer(URL: NSURL(string:"http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer")) | |
self.mapView.addMapLayer(basemap) | |
self.mapView.addGestureRecognizer(self.singleFingerZoomGesture) | |
} | |
override func didReceiveMemoryWarning() { | |
super.didReceiveMemoryWarning() | |
// Dispose of any resources that can be recreated. | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment