Skip to content
This repository was archived by the owner on May 23, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Sources/CustomAnnotatedMap/Helpers/MapKit.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// MapKit.swift
//
//
// Created by Jiří Buček on 28.07.2022.
//

import Foundation
import MapKit

extension CLLocationCoordinate2D {

func equals(to other: CLLocationCoordinate2D) -> Bool {
latitude == other.latitude
&& longitude == other.longitude
}

}

extension MKCoordinateRegion {

func equals(to other: MKCoordinateRegion) -> Bool {
center.equals(to: other.center)
&& span.equals(to: other.span)
}

}

extension MKCoordinateSpan {

func equals(to other: MKCoordinateSpan) -> Bool {
latitudeDelta == other.latitudeDelta
&& longitudeDelta == other.longitudeDelta
}

}
59 changes: 28 additions & 31 deletions Sources/CustomAnnotatedMap/_CustomAnnotatedMapContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,8 @@ where
updateAnnotationsIfNeeded(on: mapView,
with: context.coordinator)

if mapView.showsUserLocation != self.showsUserLocation {
mapView.showsUserLocation = self.showsUserLocation
}

if let userTrackingMode = MKUserTrackingMode(rawValue: self.userTrackingMode.rawValue),
mapView.userTrackingMode != userTrackingMode
{
performWithoutLocationUpdates(on: context.coordinator) {
mapView.setUserTrackingMode(userTrackingMode, animated: true)
}
}
updateUserTrackingMode(on: mapView,
with: context.coordinator)

// Update the map region either using the coordinateRegion or MapRect
if let coordinateRegion = self.coordinateRegion {
Expand All @@ -134,6 +125,24 @@ where
}
}

/// Updates the user tracking mode when it is different than the currently set mode
/// - Parameters:
/// - mapView: The MKMapView associated with this UIViewRepresentable
/// - coordinator: The associated coordinator object
private func updateUserTrackingMode(on mapView: MKMapView, with coordinator: Coordinator) {
DispatchQueue.main.async {
if mapView.showsUserLocation != self.showsUserLocation {
mapView.showsUserLocation = self.showsUserLocation
}

if let userTrackingMode = MKUserTrackingMode(rawValue: self.userTrackingMode.rawValue),
mapView.userTrackingMode != userTrackingMode
{
mapView.setUserTrackingMode(userTrackingMode, animated: true)
}
}
}


/// Checks if the current annotations reflect the annotations displayed in the map and updates accordingly
/// - Parameters:
Expand All @@ -160,28 +169,16 @@ where
/// - coordinateRegion: The region the map will be moved to
/// - mapView: The MKMapView associated with this UIViewRepresentable
/// - coordinator: The associated coordinator object
private func updateRegion(_ coordinateRegion: CoordinateRegion, on mapView: UIViewType, with coordinator: Coordinator) {
// Prevents repetitive calls to MKMapView.setRegion when other parts of the view are updated that are not
// related to the map region
guard !coordinateRegion.mapRect.isSame(as: coordinator.lastMapRect) else {
private func updateRegion(_ coordinateRegion: CoordinateRegion,
on mapView: UIViewType,
with coordinator: Coordinator) {
DispatchQueue.main.async {
guard !coordinateRegion.rawValue.equals(to: mapView.region),
!coordinator.regionIsChanging
else {
return
}

performWithoutLocationUpdates(on: coordinator) {
mapView.setRegion(coordinateRegion.rawValue, animated: true)
}
}

/// Pauses the location updates on the coordinator while performing a task
/// - Parameters:
/// - coordinator: The associated Coordinator object
/// - task: The task to be performed
private func performWithoutLocationUpdates(on coordinator: _CustomAnnotatedMapCoordinator, task: () -> Void) {
defer {
coordinator.listenToLocationChanges = true
mapView.setRegion(coordinateRegion.rawValue, animated: true)
}

coordinator.listenToLocationChanges = false
task()
}
}
33 changes: 15 additions & 18 deletions Sources/CustomAnnotatedMap/_CustomAnnotatedMapCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ extension _CustomAnnotatedMapContent {

public class _CustomAnnotatedMapCoordinator: NSObject, MKMapViewDelegate {
private var mapContent: _CustomAnnotatedMapContent
/// Determines if changes in map region are updated to the mapContent view
var listenToLocationChanges = false

/// The latest map region that got updated to the mapContent view
var lastMapRect: MapRect?
/// Determines if the map region is currently being changed with animation (the map is sliding to a new region)
var regionIsChanging = false

/// The IDs of the annotations currently displayed in the mapContent view
var displayedAnnotationsIDs: Set<ID> = []
Expand All @@ -19,21 +16,21 @@ extension _CustomAnnotatedMapContent {
self.mapContent = mapContent
super.init()
}

public func mapView(
_ mapView: MKMapView,
regionDidChangeAnimated animated: Bool
) {
/*
Only update the map region changes to the mapContent if allowed.
This prevents updates during the manual changes to the map region and user tracking mode
which are animated and would be interrupted.
*/
guard listenToLocationChanges else { return }


/// Called multiple times when the map region change animation is taking place
public func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
self.mapContent.coordinateRegion = CoordinateRegion(rawValue: mapView.region)
self.mapContent.mapRect = MapRect.init(rawValue: mapView.visibleMapRect)
self.lastMapRect = MapRect.init(rawValue: mapView.visibleMapRect)
}

/// The map view is about to change the visible map region
public func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
regionIsChanging = true
}

/// The map view finished changing the visible map region
public func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
regionIsChanging = false
}

public func mapView(
Expand Down