Some facts about me:
- Studying at Technical University Munich (Informatics M.Sc.) 🎓
- Working at QuickBird as Software Engineer 👨🏼💻
- Constantly learning, developing, trying out new things and finding better ways to solve problems 🌱
MKMapView wrapper for SwiftUI as drop-in to MapKit's SwiftUI view. Easily extensible annotations and overlays, iOS 13 support and backwards compatible with MKAnnotation and MKOverlay!
License: MIT License
Some facts about me:
We can't run this project using Xcode .
It was Building as well but it's didn't run on simulator?
Using MapAnnotation I can change the coordinate of an item and it changes on the map. However if I use ViewMapAnnotation, it doesn't change the location.
Here is a code example. Using MapAnnotation you can see the point move around. If you change it to ViewMapAnnotation, the point doesn't move at all.
import SwiftUI
import MapKit
import Map
struct ContentView: View {
@State private var map = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 40.4, longitude: -3.7),
span: MKCoordinateSpan(latitudeDelta: 2, longitudeDelta: 2)
)
@State var locations = [
MyLocation(coordinate:CLLocationCoordinate2D(latitude:40.4, longitude: -3.7))]
var body: some View {
Map(
coordinateRegion: $map,
annotationItems: locations,
annotationContent: { location in
MapAnnotation(coordinate: location.coordinate) { // Change MapAnnotation to ViewMapAnnotation here
Circle()
.frame(width: 25, height: 25)
.foregroundColor(.red)
}
}
)
.task({
while(true)
{
try? await Task.sleep(nanoseconds: 1_000_000_000)
locations[0].coordinate = CLLocationCoordinate2D(
latitude: 40.4 + Double.random(in: -0.5...0.5),
longitude: -3.7 + Double.random(in: -0.5...0.5))
}
})
}
}
struct MyLocation : Identifiable {
let id = UUID()
var coordinate: CLLocationCoordinate2D
}
Hi there and thanks for the good work!
when writing the following:
@State private var userTrackingMode = MapUserTrackingMode.follow
I get the following error: Ambiguous use of 'follow'
Hope not to bother you with typical newbie stupid stuff, but cannot find a way to go around this...
What should happen if an annotation is selected, should there be an option to handle these cases?
I'd like to display Annotations differently depending on the current zoom factor. Is there a way to access the current zoom factor? I couldn't find it... Thanks !
Looks like a great project, thanks for your work! Is it possible to click on a view in ViewMapAnnotation to bring up a small window with more information? I tried putting a Button in it, or just a TapGesture and clicking on it would display a different view, but it didn't work.
iOS 15 - SwiftUI - Xcode 13.4 - Swift Package Manager
I'm having trouble getting a demo app to compile and run. Would you be willing to create a very simple example app to get a new users for your package up and running?
I'm trying to use Map library to implement a Map where is showed some ViewMapAnnotation, as much as the user wants to show, but I'm not able to show a simple Text under the Image that represents the single annotation
This is my code for the map implementation:
Map(coordinateRegion: $searchService.region,
type: selectedMapStyle,
pointOfInterestFilter: .excludingAll,
informationVisibility: .default.union(.userLocation),
interactionModes: .all,
userTrackingMode: $userTracking,
annotationItems: selectedLandmark,
annotationContent: { location in
ViewMapAnnotation(coordinate: location.coordinate, title: location.name) {
VStack{
Image(systemName: "mappin.circle.fill")
.foregroundColor(.red)
.font(.title)
.padding()
Text("\(location.name)")
.font(.caption2)
}
}
},
overlays: renderRoutes.map {$0.polyline},
overlayContent: {overlay in
RendererMapOverlay(overlay: overlay) {_, overlay in
guard let polyline = overlay as? MKPolyline else {
assertionFailure("Unknown overlay type encountered!")
return MKOverlayRenderer(overlay: overlay)
}
let isAndataRoute = polyline === andataRoutes.first?.polyline
let renderer = MKPolylineRenderer(polyline: polyline)
renderer.lineWidth = 4
renderer.strokeColor = isAndataRoute ? .systemBlue : .systemCyan
updateRectRegion(rectangle: overlay.boundingMapRect)
return renderer
}
}
)
.ignoresSafeArea()
.background(
RoundedRectangle(cornerRadius: 30)
)
I really hope that someone can help me because this is a project that I'm developing for the final exam at university 😄
P.S. Sorry, but I'm not able to use properly the code function of GitHub because every time that I paste the code, GitHub adds to it a lot of tab at the beginning of every line
Not sure if the problem comes from your package or from MapKit directly. Whenever I add MapAnnotations, these are not centered on their middle point and rotate around another near point when rotating the map
The crazy thing is that this does not always happen. Rarely, after the app being compiled, it works perfectly...
This is not an issue perse but more like a feature request, the README.md has a few lines on how to draw polylines on map elements but doesn't seem to work or is not clear, is possible to add a basic example (even here, if it works ill create a pull request) of a basic implementation.
Thanks
I am not sure if this is related to #12 or not to be honest. It could just be me being pretty new to Map.
Hi,
trying to render some images on top of a map on my Apple Watch (rain radar gifs on top of map)
I did this on the web previously and thought, gee, that'd be nice on my wrist!
Having some difficulty trying to render images on the map, I found your library.
After adding it... Found this #if !os(watchOS)
... code ... #endif
Bummer.
So, simple question, is it a case of impossible at the moment or ... something else? It seems deliberate!
thanks for your time,
keyle
The onTapGesture is not working inside the ViewMapAnnotation, here is my code:
`Map(
coordinateRegion: $region,
type: .standard,
pointOfInterestFilter: .includingAll,
interactionModes: [.all],
annotationItems: evChargerManager.evChargers,
annotationContent: { charger in
ViewMapAnnotation(coordinate: (charger.addressInfo?.coordinates)!) {
Image(K.Images.SupplementarilyIcons.pinpoint)
.resizable()
.frame(width: 40, height: 40, alignment: .center)
.onTapGesture {
showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
EVChargerView(evCharger: charger)
} //: SHEET
} //: VIEW MAP ANNOTATION
} //: ANNOTATION CONTENT
) //: MAP`
I tried following the directions in your readme and here online, however I am getting an error when trying to set the userTrackingMode -> Cannot find 'UserTrackingMode' in scope
@State private var userTrackingMode = UserTrackingMode.follow
If I try setting to this
@State private var userTrackingMode = MapUserTrackingMode.follow
I get the following error -> Ambiguous use of 'follow'
Any help would be appreciated.
Possible additional appearance configurations:
M1 iMac
macOS 13.2.1
Xcode 14.3
Haven't dove into the code, but compilation for macOS arm64 yields the following log excerpt:
SwiftCompile normal arm64 [PATH]/Map/Sources/Map/Map.swift (in target 'Map' from project 'Map')
...
[PATH]/Map/Sources/Map/Map.swift:55:139: error: contextual closure type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?' expects 2 arguments, but 1 was used in closure body
@OptionalMapAnnotationBuilder clusterAnnotation: @escaping (MKClusterAnnotation, [AnnotationItems.Element]) -> MapAnnotation? = { _ in nil },
^
,_
[PATH]/Map/Sources/Map/Map.swift:55:137: error: generic parameter 'AnnotationItems' could not be inferred
@OptionalMapAnnotationBuilder clusterAnnotation: @escaping (MKClusterAnnotation, [AnnotationItems.Element]) -> MapAnnotation? = { _ in nil },
^
[PATH]/Map/Sources/Map/Map.swift:13:19: note: 'AnnotationItems' declared as parameter to type 'Map'
public struct Map<AnnotationItems: RandomAccessCollection, OverlayItems: RandomAccessCollection>
^
[PATH]/Map/Sources/Map/Map.swift:285:32: error: extra argument 'clusterAnnotation' in call
clusterAnnotation: { annotation, _ in clusterAnnotation(annotation) },
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[PATH]/Map/Sources/Map/Map.swift:493:32: error: cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
clusterAnnotation: clusterAnnotation,
^
[PATH]/Map/Sources/Map/Map.swift:493:32: error: cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
clusterAnnotation: clusterAnnotation,
^
[PATH]/Map/Sources/Map/Map.swift:524:32: error: cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
clusterAnnotation: clusterAnnotation,
^
[PATH]/Map/Sources/Map/Map.swift:524:32: error: cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
clusterAnnotation: clusterAnnotation,
^
[PATH]/Map/Sources/Map/Map.swift:558:32: error: cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
clusterAnnotation: clusterAnnotation,
^
[PATH]/Map/Sources/Map/Map.swift:558:32: error: cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
clusterAnnotation: clusterAnnotation,
^
[PATH]/Map/Sources/Map/Map.swift:592:32: error: cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
clusterAnnotation: clusterAnnotation,
^
[PATH]/Map/Sources/Map/Map.swift:592:32: error: cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
clusterAnnotation: clusterAnnotation,
^
[PATH]/Map/Sources/Map/Map.swift:711:32: error: contextual closure type '(MKClusterAnnotation, [IdentifiableObject<any MKAnnotation>]) -> (any MapAnnotation)?' expects 2 arguments, but 1 was used in closure body
clusterAnnotation: { clusterAnnotation($0.map(\.object)) },
^
[PATH]/Map/Sources/Map/Map.swift:711:55: error: value of type 'MKClusterAnnotation' has no member 'map'
clusterAnnotation: { clusterAnnotation($0.map(\.object)) },
~~ ^~~
[PATH]/Map/Sources/Map/Map.swift:711:59: error: cannot infer key path type from context; consider explicitly specifying a root type
clusterAnnotation: { clusterAnnotation($0.map(\.object)) },
^
<#Root#>
[PATH]/Map/Sources/Map/Map.swift:745:32: error: contextual closure type '(MKClusterAnnotation, [IdentifiableObject<any MKAnnotation>]) -> (any MapAnnotation)?' expects 2 arguments, but 1 was used in closure body
clusterAnnotation: { clusterAnnotation($0.map(\.object)) },
^
[PATH]/Map/Sources/Map/Map.swift:745:55: error: value of type 'MKClusterAnnotation' has no member 'map'
clusterAnnotation: { clusterAnnotation($0.map(\.object)) },
~~ ^~~
[PATH]/Map/Sources/Map/Map.swift:745:59: error: cannot infer key path type from context; consider explicitly specifying a root type
clusterAnnotation: { clusterAnnotation($0.map(\.object)) },
^
<#Root#>
[PATH]/Map/Sources/Map/Map.swift:782:32: error: contextual closure type '(MKClusterAnnotation, [IdentifiableObject<any MKAnnotation>]) -> (any MapAnnotation)?' expects 2 arguments, but 1 was used in closure body
clusterAnnotation: { clusterAnnotation($0.map(\.object)) },
^
[PATH]/Map/Sources/Map/Map.swift:782:55: error: value of type 'MKClusterAnnotation' has no member 'map'
clusterAnnotation: { clusterAnnotation($0.map(\.object)) },
~~ ^~~
[PATH]/Map/Sources/Map/Map.swift:782:59: error: cannot infer key path type from context; consider explicitly specifying a root type
clusterAnnotation: { clusterAnnotation($0.map(\.object)) },
^
<#Root#>
[PATH]/Map/Sources/Map/Map.swift:55:139: Contextual closure type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?' expects 2 arguments, but 1 was used in closure body
[PATH]/Map/Sources/Map/Map.swift:55:137: Generic parameter 'AnnotationItems' could not be inferred
[PATH]/Map/Sources/Map/Map.swift:285:32: Extra argument 'clusterAnnotation' in call
[PATH]/Map/Sources/Map/Map.swift:493:32: Cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
[PATH]/Map/Sources/Map/Map.swift:493:32: Cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
[PATH]/Map/Sources/Map/Map.swift:524:32: Cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
[PATH]/Map/Sources/Map/Map.swift:524:32: Cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
[PATH]/Map/Sources/Map/Map.swift:558:32: Cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
[PATH]/Map/Sources/Map/Map.swift:558:32: Cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
[PATH]/Map/Sources/Map/Map.swift:592:32: Cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
[PATH]/Map/Sources/Map/Map.swift:592:32: Cannot convert value of type '([AnnotationItems.Element]) -> (any MapAnnotation)?' to expected argument type '(MKClusterAnnotation, [AnnotationItems.Element]) -> (any MapAnnotation)?'
[PATH]/Map/Sources/Map/Map.swift:711:32: Contextual closure type '(MKClusterAnnotation, [IdentifiableObject<any MKAnnotation>]) -> (any MapAnnotation)?' expects 2 arguments, but 1 was used in closure body
[PATH]/Map/Sources/Map/Map.swift:711:55: Value of type 'MKClusterAnnotation' has no member 'map'
[PATH]/Map/Sources/Map/Map.swift:711:59: Cannot infer key path type from context; consider explicitly specifying a root type
[PATH]/Map/Sources/Map/Map.swift:745:32: Contextual closure type '(MKClusterAnnotation, [IdentifiableObject<any MKAnnotation>]) -> (any MapAnnotation)?' expects 2 arguments, but 1 was used in closure body
[PATH]/Map/Sources/Map/Map.swift:745:55: Value of type 'MKClusterAnnotation' has no member 'map'
[PATH]/Map/Sources/Map/Map.swift:745:59: Cannot infer key path type from context; consider explicitly specifying a root type
[PATH]/Map/Sources/Map/Map.swift:782:32: Contextual closure type '(MKClusterAnnotation, [IdentifiableObject<any MKAnnotation>]) -> (any MapAnnotation)?' expects 2 arguments, but 1 was used in closure body
[PATH]/Map/Sources/Map/Map.swift:782:55: Value of type 'MKClusterAnnotation' has no member 'map'
[PATH]/Map/Sources/Map/Map.swift:782:59: Cannot infer key path type from context; consider explicitly specifying a root type
Hi, I'm developing an application in SwifUI to estimate the power consumption of an e-bike based on the track chosen by the user; I'm implementing a Map initializing it as showed in the example file, but when I try to show also user position the map doesn't show the location.
I have implemented a CLLocationManager to manage user position and it works correctly, but in the example is not specified very well how to link the two components.
In my app a timer updates the positions every 15 seconds, but I don't want the old Annotation to be deleted and a new one created. The goal would be to update the annotation position with animation. Is this possible?
Hello,
I already posted this issue 3 weeks ago and I would like to give it another go if anyone has any ideas how to fix this. Thank you!
Yours faithfully,
Iraklis Eleftheriadis
Dear Paul,
I added your package 'Map' to my project as explained by Apple.
My project has a working map based on MapKit but I want to use extended facilities based on your package.
It is visible as a Package dependency as well as listed under'Frameworks, Libraries and embedded Content'.
However it seems not to be recognised by Xcode as I get 'Cannot find type 'MKCoordinateRegion' in scope and similar errors for MyLocation, MKDirections and UserTrackingMode.
Any ideas how to resolve this.
Kind regards, ahartman, belgium
Allow setting of a CameraZoomRange, CameraBoundary and MKCamera.
I'm getting runtime error: Map+Coordinator.swift:256 Modifying state during view update, this will cause undefined behavior.
The warning pops up when I'm trying to change userTrackingMode
on the button click. The code is pretty simple:
Button(action: {
userTrackingMode = .follow
}) {
Image(systemName: "location")
}
Hello!
I have a filter system in my App, which basically filters the visible annotations on the map. Based on some values, I show the appropriate annotations. I also cluster those annotations if needed. However, I noticed that if the annotation that I remove because of the new filter settings, is still in the clustering group, it throws the error assertionFailure("Somehow a cluster contains an unknown annotation item."). I guess I have to update all my clusters as I update my array of annotations. How do I do that? Thank you!
Yours faithfully,
Iraklis Eleftheriadis
Hello !
Thanks for the great work in this project !
I just Have a small issues when using map annotations.
I've got a structured array :
var places: [PointOfInterest] = []
struct PointOfInterest: Identifiable {
let id = UUID()
let name: String
let latitude: Double
let longitude: Double
var coordinate: CLLocationCoordinate2D {
CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
}
And I use it like this in my Map :
Map(coordinateRegion: $region, type: getTypeFromUD(), annotationItems: places, annotationContent: { item in
MapMarker(coordinate: item.coordinate, tint: UIColor(.red))
})
My array receive data during the user use the app. When I go to my view where is my map I see only 1 pin which isn't at a corresponding place in my array. But can't see the other ?
I don't know how to deal with that ?
When I use ignoreSafeArea or edgesIgnoringSafeArea(.all) in my code and if I zoom, my annotations aren't immobile and move.
To fix the problem I have to add a title with a VStack above my map
Some one have an idea of the problem ?
Thank you
Good work with the package, it's really impressive
Carte(coordinateRegion: $region ,type: MKStandardMapConfiguration() , userTrackingMode: $userTrackingMode ,annotationItems: MockedDataMapAnnotation,
annotationContent: { location in
CarteAnnotation(coordinate: CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)) {
VStack(spacing: 0) {
Image(systemName: "map")
.resizable()
.scaledToFit()
.frame(width: 15, height: 15)
.font(.headline)
.foregroundColor(Color.black)
.padding(6)
.background(Color.white)
.clipShape(Circle())
Image(systemName: "triangle.fill")
.resizable()
.scaledToFit()
.foregroundColor(.black)
.frame(width: 10, height: 10)
.rotationEffect(Angle(degrees: 180))
.offset(y: -1.5)
.padding(.bottom, 40)
}
}
},
overlays: [
MKPolyline(coordinates: polylineCoordinates, count: polylineCoordinates.count)
],overlayContent: { overlay in
RendererCarteOverlay(overlay: overlay) { _, overlay in
if let polyline = overlay as? MKPolyline {
let renderer = MKPolylineRenderer(polyline: polyline)
renderer.lineWidth = 2
renderer.lineCap = .butt
renderer.lineJoin = .miter
renderer.miterLimit = 0
renderer.lineDashPhase = 0
renderer.lineDashPattern = [10,5]
renderer.strokeColor = .orange
return renderer
} else {
assertionFailure("Unknown overlay type found.")
print("Probleme overlay")
return MKOverlayRenderer(overlay: overlay)
}
}
}
).edgesIgnoringSafeArea(.all)
Hello @pauljohanneskraft , loving your library!
Is there a way to support annotation selection? I already tried with navigationLinks and tapGestures with no luck
Thanks
I'm trying to make an annotation with text and icon (like the official POI's in apple maps) but the text is not displayed.
This is the code I'm using, with SwiftUI maps it works but with this library it doesn't.
Map(
coordinateRegion: $region,
pointOfInterestFilter: .excludingAll,
annotationItems: POIList){ item in
ViewMapAnnotation(coordinate: item.coordinate) {
VStack{
Text("Text Here")
Image(systemName: "leaf.circle.fill")
}
//MapPOIElementView(POI: item)
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.