How can I detect if a marker has been clicked on ?
here is my code :
let Meridian = GMSMarker()
Meridian.position = CLLocationCoordinate2D(latitude: 5.654874, longitude: 100.5320142)
Meridian.title = "Recycling Factory"
Meridian.snippet = "Meridian World Sdn Bhd"
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.showMeridianInfo))
Meridian.addGestureRecognizer(tapGesture)//here is where I get the error
#objc func showMeridianInfo (sender: UITapGestureRecognizer) {
print("meradin")
}
you have to conform to GMSMapViewDelegate and implement the:
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {}
within this function you have access to the selected marker details like title and etc.
marker.title
Related
I have set up a single marker on the map view and I am using GMSMapViewDelegate and implementing the following functions:
mapView:didBeginDraggingMarker:
mapView:didEndDraggingMarker:
mapView:didDragMarker:
I have tried reinstalling the pods but nothing I do seems to work. I have been stuck on this problem for the past 5 days and still no luck.
import GoogleMaps
class MapViewController: UIViewController, GMSMapViewDelegate {
let marker = GMSMarker()
var mapView = GMSMapView()
override func viewDidLoad() {
super.viewDidLoad()
// This function fetches data from the server and places marker
makeRequest()
self.marker.isDraggable = true
// Create a map with the location based on user's country
let camera = GMSCameraPosition.camera(withLatitude: defaults.value(forKey: map.lat) as! CLLocationDegrees,
longitude: defaults.value(forKey: map.lon) as! CLLocationDegrees,
zoom: defaults.value(forKey: map.zoom) as! Float)
mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
}
func mapView(_ mapView: GMSMapView, didBeginDragging marker: GMSMarker) {
print("DidBeginDragging")
}
func mapView(_ mapView: GMSMapView, didEndDragging marker: GMSMarker) {
print("didEndDragging")
}
func mapView(_ mapView: GMSMapView, didDrag marker: GMSMarker) {
print("didDrag")
}
}
I can drag the marker but I cannot seem to run the three delegate functions.
Looks like you missed setting the delegate:
mapView.delegate = self
at the top change the var mapView = GMSMapView() to var mapView: GMSMapView?
The way you have it, you're creating a mapView and then creating a new one in viewDidLoad
Documentation
----------UPDATED------------
original question at the bottom
I've gotten pretty far, and I have this now:
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet var mapView: MKMapView!
var locationManager: CLLocationManager!
var mapOverlay: MKOverlay!
override func viewDidLoad() {
super.viewDidLoad()
var points = [CLLocationCoordinate2D(latitude: -29.8122, longitude: 148.6351),
CLLocationCoordinate2D(latitude: -27.9307, longitude: 148.6351),
CLLocationCoordinate2D(latitude: -27.9307, longitude: 150.9909),
CLLocationCoordinate2D(latitude: -29.8122, longitude: 150.9909)]
let tile = MKPolygon(coordinates: &points, count: points.count)
tile.title = "zurich"
mapView.addOverlay(tile)
//Setup our Location Manager
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
//Setup our Map View
mapView.delegate = self
mapView.mapType = MKMapType.satellite
mapView.showsUserLocation = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// mapView delegate function
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolygonRenderer(overlay: overlay)
renderer.fillColor = UIColor.red
return renderer
}
}
I now need to know how to replace the renderer.fillColor = UIColor.red with something that will display my image.
Thanks once again
----- original question ------
So, I'm new to Swift and MapKit and I want to add a simple image overlay on top of an MKMapView. I've found a few answers, but they're all confusing, and they are all for Swift 3 and earlier.
I've found that a delegate for the map view is needed, is that a file?
I have already created a map view using the main view controller.
This is what I've done so far (this is in the ViewController.swift file):
import UIKit
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate
{
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib
let location = CLLocationCoordinate2D(latitude: 47.457925,
longitude: 8.548466)
let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
let region = MKCoordinateRegion(center: location, span: span)
mapView.setRegion(region, animated: true)
}
}
Thank you and I hope you can help!
There are a lot of way to embed image into your maps.
Annotation Views
Callouts
Custom Map Tile
Explain your need more, and maybe we can help better to how to get there.
You are adding overlay over the map. We want to change with specific map tile.
func createLocalUrl(forImageNamed name: String) -> URL? {
let fileManager = FileManager.default
let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0]
let url = cacheDirectory.appendingPathComponent("\(name).png")
guard fileManager.fileExists(atPath: url.path) else {
guard
let image = UIImage(named: name),
let data = image.pngData()
else { return nil }
fileManager.createFile(atPath: url.path, contents: data, attributes: nil)
return url
}
return url
}
func setupTiles() {
let url = createLocalUrl(forImageNamed: "yourImageName")
let template = url?.absoluteString
let overlay = MKTileOverlay(urlTemplate: template)
overlay.canReplaceMapContent = true
self.tileOverlay = overlay
mapView.addOverlay(overlay)
self.tileRenderer = MKTileOverlayRenderer(tileOverlay: overlay)
}
func isInDesiredArea(middlePoint: MKMapPoint) -> Bool {
//mapView has convert function which converts CGPoint ->
//CLLocationCoordinate2D and vice versa Use this function and,
//Your polygon has boundingMapRect which has contains function.
//Also your map has func mapView(_ mapView: MKMapView,
//regionDidChangeAnimated animated: Bool) which runs whenever region changes..
return myBoundsPolygon.boundingMapRect.hasContain(middlePoint)
}
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
//Convert middle point of your view to CLLocationCoordinate2D
//Convert your coordinate to MKMapPoint
if isInDesiredArea(middlePoint: point) {
setupTiles()
}
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
....
if overlay is MKTileOverlay {
return tileRenderer
}
I am using Mapbox to create my app. When I click a button I would like it to mark my current location and add a marker to it as it currently does. I then would like the abiilty to tap on this marker and have it display the current location information such as the adress of the marked point.
Right now all I have is...
https://imgur.com/a/RSx0G
I would like to note that I am using Xcode 9.1 and Swift 4. Thank you for all your feedback in advance.
Currently the swift file looks like...
import Foundation
import UIKit
import CoreLocation
import Mapbox
import MapKit
import MapboxGeocoder
class SecondViewController: UIViewController, CLLocationManagerDelegate, MGLMapViewDelegate, UITextFieldDelegate {
let geocoder = Geocoder.shared
let dismissesAutomatically: Bool = false
let isAnchoredToAnnotation: Bool = true
weak var delegate: MGLCalloutViewDelegate?
let tipHeight: CGFloat = 10.0
let tipWidth: CGFloat = 20.0
#IBOutlet var mapView: MGLMapView!
let manager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func markStuff(_ sender: Any) {
}
#IBAction func refLocation(_ sender: Any) {
manager.startUpdatingLocation()
}
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
return nil
}
func mapView(_ mapView: MGLMapView, tapOnCalloutFor annotation: MGLAnnotation)
{
print("tap on callout")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
mapView.setCenter(center, zoomLevel: 10, animated: true)
let annotation = MGLPointAnnotation()
annotation.coordinate = location.coordinate
mapView.selectAnnotation(annotation, animated: true)
annotation.title = "Testing"
annotation.subtitle = "\(annotation.coordinate.latitude), \(annotation.coordinate.longitude)"
self.mapView.addAnnotation(annotation)
manager.stopUpdatingLocation()
You can create a subclass of MGLUserLocationAnnotationView, then use that as your view for the MGLUserLocation annotation.
For example, if your custom subclass was called YourLocationAnnotationView(), you could do something like:
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {This custom view is created below.
if annotation is MGLUserLocation && mapView.userLocation != nil {
return YourLocationAnnotationView()
}
return nil
}
}
For a complete implementation, see this example from the official documentation.
I am making a Swift application that uses MKPointAnnotations, and I recently ran into an issue where I needed to store metadata in my annotations, so I created the custom class below:
class BRETTFAnnotation: MKPointAnnotation {
var tag: Int64
var name: String
init(lat : Double, lon:Double, t : Int64, n: String) {
self.tag = t
self.name = n
super.init()
self.coordinate = CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
}
My MKAnnotationView viewfor MKAnnotation method is shown below:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let newAnnotation = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "reuse")
newAnnotation.canShowCallout = true
let right = self.button(title: "Yes")
right?.addTarget(self, action: #selector(clickedToConfirmNewPoint), for: .touchUpInside)
newAnnotation.rightCalloutAccessoryView = right
let left = self.button(title: "No")
left?.addTarget(self, action: #selector(clickedToCancelNewPoint), for: .touchUpInside)
newAnnotation.leftCalloutAccessoryView = left
return newAnnotation
}
The problem I am running into is when ever I click on my custom BRETTFAnnotation (which I add to my MKMapView) nothing happens. When I was just using the MKPointAnnotation (instead of the BRETTFAnnotation) when I clicked on the map the two buttons on the MKAnnotationView would show. I am trying to get the MKPinAnnotationView to show on touch using my BRETTFAnnotation instead of the MKPointAnnotation.
How can I continue to use my custom annotation and show the callout when the user clicks on the annotation at the same time?
Edit 1: Since it is probably useful the code below is how I make the annotation and add it to the mapView.
let location = gestureRecognizer.location(in: mapView)
let coordinate = mapView.convert(location,toCoordinateFrom: mapView)
print("adding lat,long \(coordinate.latitude),\(coordinate.longitude)")
lastPoint = BRETTFAnnotation(lat: coordinate.latitude, lon: coordinate.longitude, t: 1, n: "")
let annotationView = MKPinAnnotationView(annotation: lastPoint, reuseIdentifier: "reuse")
mapView.addAnnotation(lastPoint)
I fix this problem by making my BRETTFAnnotation a subclass of NSObject and MKAnnotation instead of MKPointAnnotation. Doing this allowed my custom class to receive user interaction and show the callouts.
When you use your own MKAnnoation you can handle your actions in didSelect. Just implement the following code.
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if let yourAnnotation = view.annotation as? BRETTFAnnotation {
//handle your meta data or/and show UIViews or whatever
}
}
with
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
//getting called when you tap on map or on another annotation (not the selected annotation before)
//hide UIViews or do whatever you want
}
That does work for me:
class ViewController: UIViewController, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
print("didSelect")
if let annoation = view.annotation as? MyAnnoation {
print("metatag \(annoation.metaTag)")
}
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
print("didDeselect")
}
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
let annotation = MyAnnoation(n: "name", m: "metaTag")
annotation.coordinate = CLLocationCoordinate2D(latitude: 50.0, longitude: 8.0)
mapView.addAnnotation(annotation)
}
}
class MyAnnoation: MKPointAnnotation {
var name: String?
var metaTag: String?
init(n: String, m: String) {
self.name = n
self.metaTag = m
}
}
I have map view and user can drag marker. When marker tapped, it display snippet that contain location of the marker.
How to get marker's longitude and latitude? if marker is dragged to another position.
Here's what I've done:
var latitude = -7.034323799999999
var longitude = 110.42400399999997
var displayAddress = [String]()
func customizeMap() {
mapView.delegate = self
let camera = GMSCameraPosition.camera(withLatitude: Double(latitude), longitude: Double(longitude), zoom: 17)
mapView.animate(to: camera)
let markerImage = UIImage(named: "ic_home_detail_marker_location")
let markerView = UIImageView(image: markerImage)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake(Double(latitude), Double(longitude))
marker.isDraggable = true
marker.iconView = markerView
marker.snippet = displayAddress[0]
mapView.selectedMarker = marker
marker.map = mapView
}
right now i'm using static longitude and latitude
For that you can use didBeginDragging marker and didEndDragging marker delegates method of GMSMapViewDelegate.
func mapView(_ mapView: GMSMapView, didDrag marker: GMSMarker) {
print("Drag")
}
func mapView(_ mapView: GMSMapView, didBeginDragging marker: GMSMarker) {
print("Old Coordinate - \(marker.position)")
}
func mapView(_ mapView: GMSMapView, didEndDragging marker: GMSMarker) {
print("New Coordinate - \(marker.position)")
}