SDK for iOS Developer's Guide

Map Gestures

The NMAMapView class responds to a number of predefined touch gestures. The default behavior of the map for each gesture type may be used as is, supplemented, or replaced entirely. The following table is a summary of the available gestures and their default behavior.

To select a visible map object, tap the screen with one finger.
To zoom the map in a fixed amount, tap the screen twice with one finger. Tap continuously to make a continuous zoom.
To zoom out a fixed amount, tap the screen with two fingers. Tap continuously to make a continuous zoom.
To move the map, press and hold one finger to the screen and move it in any direction.
To tilt the map, press and hold two fingers to the screen in a horizontal orientation, then move them in a vertical direction.

To rotate the map around the screen center, press and hold two fingers to the screen, then move them in a horizontal direction.

Note: If two-finger panning is used during a pinch or rotate gesture, the map pans instead of tilt or rotate.
To pan the map with momentum, press and swipe one finger on the screen. The map continues to move in the same direction and gradually slows down to a stop.
To continuously zoom in or out, press and hold two fingers to the screen and increase or decrease the distance between them.
To rotate the map, press and hold two fingers to the screen and rotate them together in a circle.

Pressing and holding one finger to the screen activates the long press gesture. This gesture does not have a predefined map action.

The time required to trigger a long press gesture can be customized using NMAMapView longPressDuration property. The default value for this property is one second.

Map Gestures Example on GitHub

You can find an example that demonstrates this feature at https://github.com/heremaps/ (Obj-C) and https://github.com/heremaps/ (Swift).

Controlling the NMAMapView Gesture Response

Any of the gestures listed above may be selectively enabled or disabled on an NMAMapView instance using enableMapGestures: and disableMapGestures: methods. These methods take a single input parameter that is an "or" combination of NMAMapGestureType values, which are defined in NMAMapGesture.h. The state of a specific gesture may be checked with isMapGestureEnabled:.

The following code shows how to disable all panning gestures:

// mapView is a valid NMAMapView instance
[mapView disableMapGestures:(NMAMapGestureTypePan | NMAMapGestureTypeTwoFingerPan)];

Gesture Delegation

For custom map gesture behaviors a gesture delegate may be installed on an instance of NMAMapView. The delegate is accessed via gestureDelegate property and must implement NMAMapGestureDelegate protocol. To replace the behavior of a given gesture, the corresponding handler method of the protocol must be implemented. Any or all of the default gesture behaviors may be replaced in this way. The following example shows how to replace the NMAMapView tap handling:

// mapView is an instance of NMAMapView
// myGestureDelegate is an instance of the custom gesture handling class
mapView.gestureDelegate = myGestureDelegate;
// In the MyGestureDelegate class definition:
@interface MyGestureDelegate : NSObject <NMAMapGestureDelegate>
@implementation MyGestureDelegate
// ...
-(void)mapView:(NMAMapView*)mapView didReceiveTapAtLocation:(CGPoint)location
{
  // Custom gesture behavior
  // Tap location is available through the "location" parameter
}
@end

If the default behavior is required in addition to the custom behavior for a given gesture type, the delegate handler method for that type should invoke the appropriate method in the NMAMapView default handler, defaultGestureHandler. E.g. the following example shows how to use the default tap gesture handling behavior from a custom tap-handling method:

-(void)mapView:(NMAMapView *)mapView didReceiveTapAtLocation:(CGPoint)location
{
  // Some custom behaviour...
  [mapView.defaultGestureHandler mapView:mapView didReceiveTapAtLocation:location];
  // More custom behaviour...
}

Any gesture types not handled by your custom gesture delegate also trigger the default behavior.

Note: Disabling the NMAMapView handling of a specific gesture type also disables the delegate handling of the same gesture type.

Gesture Delegation through Recognizers

Note: As of version 2.1 these types of handler methods are deprecated. It is recommended that you migrate to delegate handler methods mentioned in the previous section.

Another way to code custom gesture behaviors is to use callback methods with UIGestureRecognizer . To replace the behavior of a given gesture, set NMAMapView usesGestureRecognizers to YES and implement the corresponding didReceive...FromRecognizer handler method from the NMAMapGesture delegate protocol. Any of the default gesture behaviors may be replaced this way. When usesGestureRecognizers is enabled, the other type of gesture delegation (as mentioned above) is disabled.

Note: The map view (or any of its subviews) intercepts all touch events delivered to it when gestures are recognized using the UIGestureRecognizer.

The following example shows how to replace the NMAMapView tap handling:


@implementation MyGestureDelegate
// ...
-(void)mapView:(NMAMapView *)mapView didReceiveTapFromRecognizer:(UITapGestureRecognizer *)recognizer
{
  // Custom gesture behavior
  // Information about the gesture is accessed through the recognizer
}
@end

Subviews

The NMAMapView class is capable of passing the detected gestures to its subviews. For this to occur, three conditions must be met:

  1. The gesture must originate inside the bounds of the subview
  2. The subview must implement the NMAMapGestureDelegate protocol
  3. The subview must implement the handler function for the type of gesture detected

Though subviews must implement the NMAMapGestureDelegate protocol to receive gestures, they do not need to be installed as the map view delegate. When a gesture is detected, the map view automatically detects whether a subview capable of handling the gesture is present. If a suitable subview is found, the gesture is passed on and the map view takes no action.

As mentioned, the map view intercepts all touch events delivered to its children. Consequently, subviews that depend on touch events (such as UIKit classes) do not function properly. If such views are required on top of the map view, they should be placed in the view hierarchy as siblings of the map view rather than children.

Note: Disabling the MapView handling of specific gesture types does not stop the map view from receiving the corresponding touch events, detecting the gestures, and passing the gestures to subviews.