I need to do something like this
a marker with a static label in google maps sdk for iOS
If there is gonna be a lot of markers, I do not recommend using iconView because it makes UI so laggy, but here it goes:
Create a UIView file as "MarkerInfoView", which will be created as MarkerInfoView.xib
Then design your UI in there, add your imageView for your icon, then add other necessary views to complete your iconView. Also include marker in the design as an imageView. Because Im not 100% sure but I think you cant use both iconView and icon in google maps.
Then create a swift file called "MarkerInfoView.swift", go to MarkerInfoView.xib and select it's class as MarkerInfoView.
Then create another swift file, lets call it PlaceMarker, inside that file you will create a class which will conform to GMSMarker, then you will initialize your view to set it equal to iconView in PlaceMarker class. Lets do it as following:
class PlaceMarker: GMSMarker {
//Initialize with lat and long, then set position equal to the coordinate.
// 'position' comes from inheriting from GMSMarker, which is google marker.
init(latitude: Double, longitude: Double, distance: Double, placeName: String) {
super.init()
if let lat: CLLocationDegrees = latitude,
let long: CLLocationDegrees = longitude {
let coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
position = coordinate
}
let view = Bundle.main.loadNibNamed("MarkerInfoView", owner: nil, options: nil)?.first as! MarkerInfoView
// you can set your view's properties here with data you are sending in initializer.
// Remember if you need to pass more than just latitude and longitude, you need
// to update initializer.
// lets say you created 2 outlet as placeNameLabel, and distanceLabel, you can set
// them like following:
view.placeNameLabel.text = placeName
view.distanceLabel.text = distance
// Once your view is ready set iconView property coming from inheriting to
// your view as following:
iconView = view
appearAnimation = .pop //not necessarily but looks nice.
}
}
Then when you have your data and your googlemaps view in a ViewController you can set like:
let latitude = 101.432432 //arbitrary, should come from your source
let longitude = 34.432124
let distance = 4
let placeName = "My place".
let marker = PlaceMarker(latitude: latitude, longitude: longitude, distance: distance, placeName: placeName)
marker.map = self.mapView // your google maps set your marker's map to it.
Related
I have a mapView in one view controller with an MKPointAnnotation. I've applied reverse Geocoder to get the street name from the coordinates and I'm trying to take that street name onto another view controller and place it into a label. But that label from the second view controller always shows the coordinates 0.0, instead of the street name.
func configureAddressNameTry() {
let vc = ViewController()
let lat = vc.annotation.coordinate.latitude
let long = vc.annotation.coordinate.longitude
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(CLLocation(latitude: lat, longitude: long)) { (placemarks, error) in
if let places = placemarks {
for place in places {
// This is the line that gives me the coordinates 0.0 (North Atlantic Ocean)
self.addressNameTry.text = place.name
}
}
}
I think I have all the necessary code for the user location and the information in the info.plist, so I don't know what I'm missing. I'm new to programming and I hope I'm not making a basic error.
Thank you for your replies :)
I have been testing out using MapBox for my SwiftUI application but I've run into issues where my annotations are not appearing on my MapView even though they appear to have been added. My code for my updateAnnotations command, which is called on updateUIView is:
private func updateAnnotations() {
if let currentAnnotations = mapView.annotations {
mapView.removeAnnotations(currentAnnotations)
}
for marker in devices.positions {
let annotation = MGLPointAnnotation(title: marker.name, coordinate: marker.coordinate)
mapView.addAnnotation(annotation)
print("ADDED \(annotation)")
print(mapView.annotations)
}
}
devices is a #ObservedObject containing a positions array of points with a title and coordinate to plot. My output from this code is:
ADDED <MGLPointAnnotation: 0x285abc9f0; title = "Test"; subtitle = (null); coordinate = -36.892800, 174.625000>
Optional([<MGLPointAnnotation: 0x2866b7c60; title = "Test"; subtitle = (null); coordinate = -36.892800, 174.625000>])
This doesn't make sense to me - the output suggests that the annotation has been created but it doesn't show up on the map. Any help would be greatly appreciated.
You need to pass in the MapView when using SwiftUI - e.g. change updateAnnotations() to updateAnnotations(_ mapView: MGLMapView)
How to display current location from coordinates manually? I am taking coordinates from another GPS device. How to set it manually?
Where the coordinates come from is largely immaterial: as long as you have one you can set the map to display an area including that point. If you want to display the point itself you can add an annotation:
A simple example method to drop a pin and zoom in to its location:
func createAnnotation(from coordinate: CLLocationCoordinate2D, title: String) -> MKPointAnnotation {
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = title
return annotation
}
func dropPinAndZoomIn(to coordinate: CLLocationCoordinate2D){
var spanDelta = 0.035 //the width/height of the map area in degrees
let annotation = createAnnotation(from: coordinate, title: "My Location")
mapView.removeAnnotations(mapView.annotations) //clear any prev annotations
mapView.addAnnotation(annotation)
let span = MKCoordinateSpan(latitudeDelta: spanDelta, longitudeDelta: spanDelta)
let region = MKCoordinateRegion(center: coordinate, span: span)
let displayRegion = mapView.regionThatFits(region) //ensure the region can be displayed in the mapView's view
mapView.setRegion(displayRegion, animated: true)
}
I'm using iOS Mapbox SDK in my app. I changed image for an annotation to a custom image (It looks like a map marker). When I add an annotation to a specific coordinate on the map view, It will be added but the center of my custom annotation image (the marker) will be set on the coordinate. I need to change the marker position to set the bottom of the marker on the coordinate. I found a way but I do not know is there a better way or not?
I converted the coordinate to a point, then changed the point y position, then converted the point to a new coordinate.
func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -> MGLAnnotationImage? {
let reuseIdentifier = "annotationImage"
var annotationImage = mapView.dequeueReusableAnnotationImage(withIdentifier: reuseIdentifier)
if annotationImage == nil {
annotationImage = MGLAnnotationImage(image: UIImage(named: "Orange")!, reuseIdentifier: reuseIdentifier)
}
return annotationImage
}
func addDestinationMarker(coordinate: CLLocationCoordinate2D) {
guard let mapView = mapView else { return }
if let annotations = mapView.annotations {
mapView.removeAnnotations(annotations)
}
var point = mapView.convert(coordinate, toPointTo: mapView)
point.y -= markerImageView.frame.height / 2
let newCoordinate = mapView.convert(point, toCoordinateFrom: mapView)
let annotation = MGLPointAnnotation()
annotation.coordinate = newCoordinate
mapView.addAnnotation(annotation)
}
I've run into this same issue and started to think that round map pins were becoming the defacto standard so they could just be plonked onto the map with the image centre denoting the coordinate. However if you take a look at this example on the Mapbox website, they use a non-round image and solve the offset problem quite nicely.
// The anchor point of an annotation is currently always the center. To
// shift the anchor point to the bottom of the annotation, the image
// asset includes transparent bottom padding equal to the original image
// height.
//
// To make this padding non-interactive, we create another image object
// with a custom alignment rect that excludes the padding.
image = image.withAlignmentRectInsets(UIEdgeInsets(top: 0, left: 0, bottom: image.size.height/2, right: 0))
This does mean that you need to generate pin images that are twice as tall, with the lower half transparent, but that's really not a big deal.
You can solve this by leveraging the centerOffset property that MGLAnnotationView provides. Though I'm not sure if it's present in the MGLAnnotationImage you're using.
To set the anchor to the bottom of the annotation, use:
centerOffset.dy = -height / 2
If you set the frame beforehand, the height is simply frame.height.
The other answers express things correctly but both are missing the correct syntax:
annotationView?.centerOffset.y = -(annotationView?.frame.height ?? 0) / 2
This will achieve the expected result.
What is the correct way to auto zoom an iOS MapKit MKMapItem generated map when it first displays using the option MKLaunchOptionsMapSpanKey:?
Specifically, how should the zoom factor be entered for MKLaunchOptionsMapSpanKey:??? (i.e. MKLaunchOptionsMapSpanKey:0.1).
Or, alternatively, is there another way programmatically to auto zoom the map when it first displays which I am not aware of?
#IBAction func getDirections(sender: AnyObject) {
let mapItem = MKMapItem.mapItemForCurrentLocation()
let coords = CLLocationCoordinate2DMake(latitude, longitude)
mapItem.name = "User Location"
let options = [MKLaunchOptionsMapSpanKey:???,MKLaunchOptionsMapCenterKey:location, ]
let place = MKPlacemark(coordinate: coords, addressDictionary:nil)
mapItem.openInMapsWithLaunchOptions(options)
}