Skip to content

Commit

Permalink
Redesign tap architecture for annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
nishant-karajgikar committed Sep 24, 2021
1 parent 1f2c128 commit 1d6c0ae
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 106 deletions.
33 changes: 18 additions & 15 deletions Sources/MapboxMaps/Annotations/AnnotationOrchestrator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,19 @@ public protocol AnnotationInteractionDelegate: AnyObject {

public class AnnotationOrchestrator {

private weak var view: UIView?
private weak var singleTapGestureRecognizer: UIGestureRecognizer?

private let style: Style

private let mapFeatureQueryable: MapFeatureQueryable

private weak var displayLinkCoordinator: DisplayLinkCoordinator?

internal init(view: UIView, mapFeatureQueryable: MapFeatureQueryable, style: Style, displayLinkCoordinator: DisplayLinkCoordinator) {
self.view = view
internal init(singleTapGestureRecognizer: UIGestureRecognizer,
mapFeatureQueryable: MapFeatureQueryable,
style: Style,
displayLinkCoordinator: DisplayLinkCoordinator) {
self.singleTapGestureRecognizer = singleTapGestureRecognizer
self.mapFeatureQueryable = mapFeatureQueryable
self.style = style
self.displayLinkCoordinator = displayLinkCoordinator
Expand All @@ -62,14 +65,14 @@ public class AnnotationOrchestrator {
public func makePointAnnotationManager(id: String = String(UUID().uuidString.prefix(5)),
layerPosition: LayerPosition? = nil) -> PointAnnotationManager {

guard let view = view,
guard let singleTapGestureRecognizer = singleTapGestureRecognizer,
let displayLinkCoordinator = displayLinkCoordinator else {
fatalError("View and displayLinkCoordinator must be present when creating an annotation manager")
fatalError("SingleTapGestureRecognizer and displayLinkCoordinator must be present when creating an annotation manager")
}

return PointAnnotationManager(id: id,
style: style,
view: view,
singleTapGestureRecognizer: singleTapGestureRecognizer,
mapFeatureQueryable: mapFeatureQueryable,
shouldPersist: true,
layerPosition: layerPosition,
Expand All @@ -84,14 +87,14 @@ public class AnnotationOrchestrator {
public func makePolygonAnnotationManager(id: String = String(UUID().uuidString.prefix(5)),
layerPosition: LayerPosition? = nil) -> PolygonAnnotationManager {

guard let view = view,
guard let singleTapGestureRecognizer = singleTapGestureRecognizer,
let displayLinkCoordinator = displayLinkCoordinator else {
fatalError("View and displayLinkCoordinator must be present when creating an annotation manager")
fatalError("SingleTapGestureRecognizer and displayLinkCoordinator must be present when creating an annotation manager")
}

return PolygonAnnotationManager(id: id,
style: style,
view: view,
singleTapGestureRecognizer: singleTapGestureRecognizer,
mapFeatureQueryable: mapFeatureQueryable,
shouldPersist: true,
layerPosition: layerPosition,
Expand All @@ -106,14 +109,14 @@ public class AnnotationOrchestrator {
public func makePolylineAnnotationManager(id: String = String(UUID().uuidString.prefix(5)),
layerPosition: LayerPosition? = nil) -> PolylineAnnotationManager {

guard let view = view,
guard let singleTapGestureRecognizer = singleTapGestureRecognizer,
let displayLinkCoordinator = displayLinkCoordinator else {
fatalError("View and displayLinkCoordinator must be present when creating an annotation manager")
fatalError("SingleTapGestureRecognizer and displayLinkCoordinator must be present when creating an annotation manager")
}

return PolylineAnnotationManager(id: id,
style: style,
view: view,
singleTapGestureRecognizer: singleTapGestureRecognizer,
mapFeatureQueryable: mapFeatureQueryable,
shouldPersist: true,
layerPosition: layerPosition,
Expand All @@ -128,14 +131,14 @@ public class AnnotationOrchestrator {
public func makeCircleAnnotationManager(id: String = String(UUID().uuidString.prefix(5)),
layerPosition: LayerPosition? = nil) -> CircleAnnotationManager {

guard let view = view,
guard let singleTapGestureRecognizer = singleTapGestureRecognizer,
let displayLinkCoordinator = displayLinkCoordinator else {
fatalError("View and displayLinkCoordinator must be present when creating an annotation manager")
fatalError("SingleTapGestureRecognizer and displayLinkCoordinator must be present when creating an annotation manager")
}

return CircleAnnotationManager(id: id,
style: style,
view: view,
singleTapGestureRecognizer: singleTapGestureRecognizer,
mapFeatureQueryable: mapFeatureQueryable,
shouldPersist: true,
layerPosition: layerPosition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class CircleAnnotationManager: AnnotationManager {
private let mapFeatureQueryable: MapFeatureQueryable

/// Dependency required to add gesture recognizer to the MapView
private weak var view: UIView?
private weak var singleTapGestureRecognizer: UIGestureRecognizer?

/// Storage for common layer properties
private var layerProperties: [String: Any] = [:] {
Expand All @@ -54,7 +54,7 @@ public class CircleAnnotationManager: AnnotationManager {

internal init(id: String,
style: Style,
view: UIView,
singleTapGestureRecognizer: UIGestureRecognizer,
mapFeatureQueryable: MapFeatureQueryable,
shouldPersist: Bool,
layerPosition: LayerPosition?,
Expand All @@ -63,7 +63,7 @@ public class CircleAnnotationManager: AnnotationManager {
self.style = style
self.sourceId = id + "-source"
self.layerId = id + "-layer"
self.view = view
self.singleTapGestureRecognizer = singleTapGestureRecognizer
self.mapFeatureQueryable = mapFeatureQueryable
self.shouldPersist = shouldPersist

Expand Down Expand Up @@ -206,36 +206,23 @@ public class CircleAnnotationManager: AnnotationManager {
}
}

// MARK: - Selection Handling -
// MARK: - Tap Handling -

/// Set this delegate in order to be called back if a tap occurs on an annotation being managed by this manager.
public weak var delegate: AnnotationInteractionDelegate? {
didSet {
if delegate != nil {
setupTapRecognizer()
} else {
guard let view = view, let recognizer = tapGestureRecognizer else { return }
view.removeGestureRecognizer(recognizer)
tapGestureRecognizer = nil
if delegate != nil && oldValue == nil {
singleTapGestureRecognizer?.addTarget(self, action: #selector(handleTap(_:)))
} else if delegate == nil && oldValue != nil {
singleTapGestureRecognizer?.removeTarget(self, action: #selector(handleTap(_:)))
}
}
}

/// The `UITapGestureRecognizer` that's listening to touch events on the map for the annotations present in this manager
public var tapGestureRecognizer: UITapGestureRecognizer?

internal func setupTapRecognizer() {
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
tapRecognizer.numberOfTapsRequired = 1
tapRecognizer.numberOfTouchesRequired = 1
view?.addGestureRecognizer(tapRecognizer)
tapGestureRecognizer = tapRecognizer
}

@objc internal func handleTap(_ tap: UITapGestureRecognizer) {
let options = RenderedQueryOptions(layerIds: [layerId], filter: nil)
mapFeatureQueryable.queryRenderedFeatures(
at: tap.location(in: view),
at: tap.location(in: tap.view),
options: options) { [weak self] (result) in

guard let self = self else { return }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class PointAnnotationManager: AnnotationManager {
private let mapFeatureQueryable: MapFeatureQueryable

/// Dependency required to add gesture recognizer to the MapView
private weak var view: UIView?
private weak var singleTapGestureRecognizer: UIGestureRecognizer?

/// Storage for common layer properties
private var layerProperties: [String: Any] = [:] {
Expand All @@ -54,7 +54,7 @@ public class PointAnnotationManager: AnnotationManager {

internal init(id: String,
style: Style,
view: UIView,
singleTapGestureRecognizer: UIGestureRecognizer,
mapFeatureQueryable: MapFeatureQueryable,
shouldPersist: Bool,
layerPosition: LayerPosition?,
Expand All @@ -63,7 +63,7 @@ public class PointAnnotationManager: AnnotationManager {
self.style = style
self.sourceId = id + "-source"
self.layerId = id + "-layer"
self.view = view
self.singleTapGestureRecognizer = singleTapGestureRecognizer
self.mapFeatureQueryable = mapFeatureQueryable
self.shouldPersist = shouldPersist

Expand Down Expand Up @@ -464,36 +464,23 @@ public class PointAnnotationManager: AnnotationManager {
}
}

// MARK: - Selection Handling -
// MARK: - Tap Handling -

/// Set this delegate in order to be called back if a tap occurs on an annotation being managed by this manager.
public weak var delegate: AnnotationInteractionDelegate? {
didSet {
if delegate != nil {
setupTapRecognizer()
} else {
guard let view = view, let recognizer = tapGestureRecognizer else { return }
view.removeGestureRecognizer(recognizer)
tapGestureRecognizer = nil
if delegate != nil && oldValue == nil {
singleTapGestureRecognizer?.addTarget(self, action: #selector(handleTap(_:)))
} else if delegate == nil && oldValue != nil {
singleTapGestureRecognizer?.removeTarget(self, action: #selector(handleTap(_:)))
}
}
}

/// The `UITapGestureRecognizer` that's listening to touch events on the map for the annotations present in this manager
public var tapGestureRecognizer: UITapGestureRecognizer?

internal func setupTapRecognizer() {
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
tapRecognizer.numberOfTapsRequired = 1
tapRecognizer.numberOfTouchesRequired = 1
view?.addGestureRecognizer(tapRecognizer)
tapGestureRecognizer = tapRecognizer
}

@objc internal func handleTap(_ tap: UITapGestureRecognizer) {
let options = RenderedQueryOptions(layerIds: [layerId], filter: nil)
mapFeatureQueryable.queryRenderedFeatures(
at: tap.location(in: view),
at: tap.location(in: tap.view),
options: options) { [weak self] (result) in

guard let self = self else { return }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class PolygonAnnotationManager: AnnotationManager {
private let mapFeatureQueryable: MapFeatureQueryable

/// Dependency required to add gesture recognizer to the MapView
private weak var view: UIView?
private weak var singleTapGestureRecognizer: UIGestureRecognizer?

/// Storage for common layer properties
private var layerProperties: [String: Any] = [:] {
Expand All @@ -54,7 +54,7 @@ public class PolygonAnnotationManager: AnnotationManager {

internal init(id: String,
style: Style,
view: UIView,
singleTapGestureRecognizer: UIGestureRecognizer,
mapFeatureQueryable: MapFeatureQueryable,
shouldPersist: Bool,
layerPosition: LayerPosition?,
Expand All @@ -63,7 +63,7 @@ public class PolygonAnnotationManager: AnnotationManager {
self.style = style
self.sourceId = id + "-source"
self.layerId = id + "-layer"
self.view = view
self.singleTapGestureRecognizer = singleTapGestureRecognizer
self.mapFeatureQueryable = mapFeatureQueryable
self.shouldPersist = shouldPersist

Expand Down Expand Up @@ -196,36 +196,23 @@ public class PolygonAnnotationManager: AnnotationManager {
}
}

// MARK: - Selection Handling -
// MARK: - Tap Handling -

/// Set this delegate in order to be called back if a tap occurs on an annotation being managed by this manager.
public weak var delegate: AnnotationInteractionDelegate? {
didSet {
if delegate != nil {
setupTapRecognizer()
} else {
guard let view = view, let recognizer = tapGestureRecognizer else { return }
view.removeGestureRecognizer(recognizer)
tapGestureRecognizer = nil
if delegate != nil && oldValue == nil {
singleTapGestureRecognizer?.addTarget(self, action: #selector(handleTap(_:)))
} else if delegate == nil && oldValue != nil {
singleTapGestureRecognizer?.removeTarget(self, action: #selector(handleTap(_:)))
}
}
}

/// The `UITapGestureRecognizer` that's listening to touch events on the map for the annotations present in this manager
public var tapGestureRecognizer: UITapGestureRecognizer?

internal func setupTapRecognizer() {
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
tapRecognizer.numberOfTapsRequired = 1
tapRecognizer.numberOfTouchesRequired = 1
view?.addGestureRecognizer(tapRecognizer)
tapGestureRecognizer = tapRecognizer
}

@objc internal func handleTap(_ tap: UITapGestureRecognizer) {
let options = RenderedQueryOptions(layerIds: [layerId], filter: nil)
mapFeatureQueryable.queryRenderedFeatures(
at: tap.location(in: view),
at: tap.location(in: tap.view),
options: options) { [weak self] (result) in

guard let self = self else { return }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class PolylineAnnotationManager: AnnotationManager {
private let mapFeatureQueryable: MapFeatureQueryable

/// Dependency required to add gesture recognizer to the MapView
private weak var view: UIView?
private weak var singleTapGestureRecognizer: UIGestureRecognizer?

/// Storage for common layer properties
private var layerProperties: [String: Any] = [:] {
Expand All @@ -54,7 +54,7 @@ public class PolylineAnnotationManager: AnnotationManager {

internal init(id: String,
style: Style,
view: UIView,
singleTapGestureRecognizer: UIGestureRecognizer,
mapFeatureQueryable: MapFeatureQueryable,
shouldPersist: Bool,
layerPosition: LayerPosition?,
Expand All @@ -63,7 +63,7 @@ public class PolylineAnnotationManager: AnnotationManager {
self.style = style
self.sourceId = id + "-source"
self.layerId = id + "-layer"
self.view = view
self.singleTapGestureRecognizer = singleTapGestureRecognizer
self.mapFeatureQueryable = mapFeatureQueryable
self.shouldPersist = shouldPersist

Expand Down Expand Up @@ -226,36 +226,23 @@ public class PolylineAnnotationManager: AnnotationManager {
}
}

// MARK: - Selection Handling -
// MARK: - Tap Handling -

/// Set this delegate in order to be called back if a tap occurs on an annotation being managed by this manager.
public weak var delegate: AnnotationInteractionDelegate? {
didSet {
if delegate != nil {
setupTapRecognizer()
} else {
guard let view = view, let recognizer = tapGestureRecognizer else { return }
view.removeGestureRecognizer(recognizer)
tapGestureRecognizer = nil
if delegate != nil && oldValue == nil {
singleTapGestureRecognizer?.addTarget(self, action: #selector(handleTap(_:)))
} else if delegate == nil && oldValue != nil {
singleTapGestureRecognizer?.removeTarget(self, action: #selector(handleTap(_:)))
}
}
}

/// The `UITapGestureRecognizer` that's listening to touch events on the map for the annotations present in this manager
public var tapGestureRecognizer: UITapGestureRecognizer?

internal func setupTapRecognizer() {
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
tapRecognizer.numberOfTapsRequired = 1
tapRecognizer.numberOfTouchesRequired = 1
view?.addGestureRecognizer(tapRecognizer)
tapGestureRecognizer = tapRecognizer
}

@objc internal func handleTap(_ tap: UITapGestureRecognizer) {
let options = RenderedQueryOptions(layerIds: [layerId], filter: nil)
mapFeatureQueryable.queryRenderedFeatures(
at: tap.location(in: view),
at: tap.location(in: tap.view),
options: options) { [weak self] (result) in

guard let self = self else { return }
Expand Down
6 changes: 5 additions & 1 deletion Sources/MapboxMaps/Foundation/MapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,11 @@ open class MapView: UIView {
location = LocationManager(style: mapboxMap.style)

// Initialize/Configure annotations orchestrator
annotations = AnnotationOrchestrator(view: self, mapFeatureQueryable: mapboxMap, style: mapboxMap.style, displayLinkCoordinator: self)
annotations = AnnotationOrchestrator(
singleTapGestureRecognizer: gestures.singleTapGestureRecognizer,
mapFeatureQueryable: mapboxMap,
style: mapboxMap.style,
displayLinkCoordinator: self)
}

private func checkForMetalSupport() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ final class MockMapViewDependencyProvider: MapViewDependencyProviderProtocol {
pitchGestureHandler: makeGestureHandler(),
doubleTapToZoomInGestureHandler: makeGestureHandler(),
doubleTouchToZoomOutGestureHandler: makeGestureHandler(),
quickZoomGestureHandler: makeGestureHandler())
quickZoomGestureHandler: makeGestureHandler(),
singleTapGestureHandler: makeGestureHandler())
}

func makeGestureHandler() -> GestureHandler {
Expand Down
Loading

0 comments on commit 1d6c0ae

Please sign in to comment.