I want to show full screen mapView, always get Latitude and longitude of center of mapView and show marker in this point.
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
let lat = mapView.camera.target.latitude
print(lat)
let lon = mapView.camera.target.longitude
print(lon)
marker.position = CLLocationCoordinate2DMake(CLLocationDegrees(centerPoint.x) , CLLocationDegrees(centerPoint.y))
marker.map = self.mapView
returnPostionOfMapView(mapView: mapView)
}
func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
print("idleAt")
//called when the map is idle
returnPostionOfMapView(mapView: mapView)
}
func returnPostionOfMapView(mapView:GMSMapView){
let geocoder = GMSGeocoder()
let latitute = mapView.camera.target.latitude
let longitude = mapView.camera.target.longitude
let position = CLLocationCoordinate2DMake(latitute, longitude)
geocoder.reverseGeocodeCoordinate(position) { response , error in
if error != nil {
print("GMSReverseGeocode Error: \(String(describing: error?.localizedDescription))")
}else {
let result = response?.results()?.first
let address = result?.lines?.reduce("") { $0 == "" ? $1 : $0 + ", " + $1 }
print(address)
// self.searchBar.text = address
}
}
}
i use this code in how can know Latitude and longitude that return in returnPostionOfMapView method is position of center mapView and show marker in this position?
You are doing it right to get the center of the map by using the google maps's func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) delegate.
Take a variable for center coordinates
var centerMapCoordinate:CLLocationCoordinate2D!
Implement this delegate to know the center position.
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
let latitude = mapView.camera.target.latitude
let longitude = mapView.camera.target.longitude
centerMapCoordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
self.placeMarkerOnCenter(centerMapCoordinate:centerMapCoordinate)
}
Function to place a marker on center point
func placeMarkerOnCenter(centerMapCoordinate:CLLocationCoordinate2D) {
let marker = GMSMarker()
marker.position = centerMapCoordinate
marker.map = self.mapView
}
In this case you will get a lot of markers. So keep a global hold of marker and check if it is already present, just change the position
var marker:GMSMarker!
func placeMarkerOnCenter(centerMapCoordinate:CLLocationCoordinate2D) {
if marker == nil {
marker = GMSMarker()
}
marker.position = centerMapCoordinate
marker.map = self.mapView
}
Related
I am using GoogleMaps to show the location marker on screens after fetching the location from Firestore database but the problem is I have three functions.
First function is showing all the list of users on the google maps, I called it in viewDidLoad() method.
func showListOfAllUsers() {
for document in snapshot!.documents {
print(document.data())
let marker = GMSMarker()
self.location.append(Location(trackingData: document.data()))
print(self.location)
guard let latitude = document.data()["Latitude"] as? Double else { return }
guard let longitude = document.data()["longitude"] as? Double else { return }
marker.position = CLLocationCoordinate2D(latitude: latitude as! CLLocationDegrees , longitude: longitude as! CLLocationDegrees)
marker.map = self.mapView
marker.userData = self.location
marker.icon = UIImage(named: "marker")
bounds = bounds.includingCoordinate(marker.position)
print("Data stored in marker \(marker.userData!)")
}
}
Now I presented a list of users in which I am passing the selected user co-ordinates to show the markers on the GoogleMaps.
func getAllLocationOfSelectedUserFromFirestore() {
for document in snapshot!.documents {
print(document.data())
let marker = GMSMarker()
self.location.append(Location(trackingData: document.data()))
print(self.location)
guard let latitude = document.data()["Latitude"] as? Double else { return }
guard let longitude = document.data()["longitude"] as? Double else { return }
marker.position = CLLocationCoordinate2D(latitude: latitude as! CLLocationDegrees , longitude: longitude as! CLLocationDegrees)
marker.map = self.mapView
marker.userData = self.location
bounds = bounds.includingCoordinate(marker.position)
print("Data stored in marker \(marker.userData!)")
}
}
I used delegate method to pass the selected user information.
extension MapViewController: ShowTrackingSalesMenListVCDelegate {
func didSelectedFilters(_ sender: ShowTrackingSalesMenListViewController, with userID: String) {
self.selectedUserID = userID
self.userLogButton.isHidden = false
print("The selected UserID is \(selectedUserID)")
self.getAllLocationOfSelectedUserFromFirestore() // called here the second function
}
Here is GMSMapViewDelegate function in which I am passing the user informations in userData.
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print("didTap marker")
self.view.endEditing(true)
self.mapView.endEditing(true)
if let _ = self.activeMarker {
self.infoWindowView.removeFromSuperview()
self.activeMarker = nil
}
self.infoWindowView = MarkerInfoView()
let point = mapView.projection.point(for: marker.position)
self.infoWindowView.frame = CGRect(x: (point.x-(self.infoWindowView.width/2.0)), y: (point.y-(self.infoWindowView.height+25.0)), width: self.infoWindowView.width, height: self.infoWindowView.height)
self.activeMarker = marker
for mark in location {
self.infoWindowView.storeNameLabel?.text = mark.name
}
print(self.infoWindowView.storeNameLabel?.text as Any)
if let data = marker.userData as? [String:Any] {
print(data)
self.storeMapData = data
print(self.storeMapData)
var name = "N/A"
if let obj = data["name"] as? String {
name = obj
}
} else {
}
infoWindowView.delegate = self
self.mapView.addSubview(self.infoWindowView)
return true
}
It is showing the marker of the selected user on GoogleMaps. Now the problem is GMSMapViewDelegate function is same for both the above functions and it is showing the markers from both the functions on map. But I want to show only the selected user information on Maps. The red marker showing the selected user locations. How can I do this?
Just put a boolean flag and when you select the user set it to true and check it in the delegate and clear map overlay and put your marker only
Using Google Maps iOS SDK, I want to be able to print the coordinates of a GMSMarker if long pressed on that particular marker.
I first get all of my coordinates from a dictionary and drop markers for all coordinates on the map:
func placeMapMarkers() {
for item in self.finalDictionary as [Dictionary<String, String>] {
let lat = item["lat"] as! String
let lon = item["lon"] as! String
let SpotLat = Double(lat)
let SpotLon = Double(lon)
let SpotLocation = CLLocationCoordinate2DMake(SpotLat!, SpotLon!)
DispatchQueue.main.async(execute: {
self.SpotMarker = GMSMarker(position: SpotLocation)
self.SpotMarker?.icon = self.imageWithImage(image: UIImage(named: "SpotIcon")!, scaledToSize: CGSize(width: 35.0, height: 35.0))
self.SpotMarker?.title = "Long press to navigate here"
self.SpotMarker?.map = self.mapView
})
longPress(mapView: self.mapView, didLongPressAtCoordinate: SpotLocation)
}
}
My longPress function call is in the above placeMapMarkers function itself, since I want to identify while placing markers itself if a particular marker has been long pressed (I could be wrong with my thinking here).
My longPress function is below.
//This is long Press function:-
func longPressView(mapView: GMSMapView!, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
//Here handle your long press on map marker like:-
print("long pressed at \(coordinate)")
}
The problem is that I am getting "long pressed at" all coordinates from the dictionary of coordinates.
I want to
place markers for all coordinates in a dictionary
long press on a particular marker
and print coordinates for only that particular marker which was long pressed.
How do I go about this? Had a look at the other solutions, wasn't able to work out much.
I looked through the GMSMapView API. There is a method called "didLongPressAtCoordinate" that passes in a CLLocationCoordinate2D, so I think you can use that to create a GMSMarker. See here
You have to implement the GMSMapViewDelegate, and you can call
func mapView(mapView: GMSMapView!, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
let marker = GMSMarker(position: coordinate)
marker.title = "Found You!"
marker.map = mapView
}
Hope this one helps :)
I have done this before. You basically have to convert the touch point on the map to a coordinate.
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
let uilpgr = UILongPressGestureRecognizer(target: self, action: #selector(userPerformedLongPress(gesture:)))
uilpgr.minimumPressDuration = 2.0
}
func userPerformedLongPress(gesture: UIGestureRecognizer) {
let touchPoint = gesture.location(in: mapView)
let newCoordinate: CLLocationCoordinate2D = mapView.convert(touchPoint, toCoordinateFrom: mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinate
annotation.title = "Location Selected"
annotation.subtitle = "Coordinate: \(round(1000*newCoordinate.longitude)/1000), \(round(1000*newCoordinate.latitude)/1000)"
mapView.addAnnotation(annotation)
print("Gesture recognized")
}
I'm using this class
import UIKit
import CoreLocation
import GoogleMaps
import GooglePlaces
import SwiftyJSON
import Alamofire
import MapKit
class FinalClass: UIViewController {
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var bottomInfoView: UIView!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var distanceLabel: UILabel!
var userLocation:CLLocationCoordinate2D?
var places:[QPlace] = []
var index:Int = -1
var locationStart = CLLocation()
var locationEnd = CLLocation()
var mapView:GMSMapView!
var marker:GMSMarker?
override func loadView() {
super.loadView()
}
override func viewDidLoad() {
super.viewDidLoad()
guard index >= 0, places.count > 0 else {
return
}
let place = places[index]
let lat = place.location?.latitude ?? 1.310844
let lng = place.location?.longitude ?? 103.866048
// Google map view
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: lng, zoom: 12.5)
mapView = GMSMapView.map(withFrame: self.view.bounds, camera: camera)
mapView.autoresizingMask = [.flexibleHeight, .flexibleWidth, .flexibleTopMargin, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin]
self.containerView.addSubview(mapView)
// Add gesture
addSwipeGesture()
didSelect(place: place)
if userLocation != nil {
addMarkerAtCurrentLocation(userLocation!)
}
}
func addSwipeGesture() {
let directions: [UISwipeGestureRecognizerDirection] = [.right, .left]
for direction in directions {
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(sender:)))
gesture.direction = direction
self.bottomInfoView.addGestureRecognizer(gesture)
}
}
func addMarkerAtCurrentLocation(_ userLocation: CLLocationCoordinate2D) {
let marker = GMSMarker()
marker.position = userLocation
marker.title = "Your location"
marker.map = mapView
}
func didSelect(place:QPlace) {
guard let coordinates = place.location else {
return
}
// clear current marker
marker?.map = nil
// add marker
marker = GMSMarker()
marker?.position = coordinates
marker?.title = place.name
marker?.map = mapView
mapView.selectedMarker = marker
moveToMarker(marker!)
// update bottom info panel view
let desc = place.getDescription()
descriptionLabel.text = desc.characters.count > 0 ? desc : "-"
distanceLabel.text = "-"
// update distance
if userLocation != nil {
let dist = distance(from: userLocation!, to: coordinates)
distanceLabel.text = String.init(format: "Distance %.2f meters", dist)
self.drawPath(startLocation: userLocation!, endLocation: coordinates)
}
title = place.name
}
func moveToMarker(_ marker: GMSMarker) {
let camera = GMSCameraPosition.camera(withLatitude: marker.position.latitude,
longitude: marker.position.longitude,
zoom: 12.5)
self.mapView.animate(to: camera)
}
// distance between two coordinates
func distance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> CLLocationDistance {
let from = CLLocation(latitude: from.latitude, longitude: from.longitude)
let to = CLLocation(latitude: to.latitude, longitude: to.longitude)
return from.distance(from: to)
}
func handleSwipe(sender: UISwipeGestureRecognizer) {
guard index >= 0, places.count > 0 else {
return
}
if sender.direction == .left {
if index < places.count - 2 {
index += 1
didSelect(place: places[index])
}
} else if sender.direction == .right {
if index > 1 {
index -= 1
didSelect(place: places[index])
}
}
}
func drawPath(startLocation: CLLocationCoordinate2D, endLocation: CLLocationCoordinate2D) {
let from = CLLocation(latitude: startLocation.latitude, longitude: startLocation.longitude)
let to = CLLocation(latitude: endLocation.latitude, longitude: endLocation.longitude)
let origin = "\(from.coordinate.latitude),\(from.coordinate.longitude)"
let destination = "\(to.coordinate.latitude),\(to.coordinate.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving"
Alamofire.request(url).responseJSON { response in
print(response.request as Any) // original URL request
print(response.response as Any) // HTTP URL response
print(response.data as Any) // server data
print(response.result as Any) // result of response serialization
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
// print route using Polyline
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.black
polyline.map = self.mapView
}
}
}
#IBAction func navigationStart(_ sender: Any) {
}
with a google maps to add place markers, draw the direction on the map and show the distance between two points, now i would like to launch the navigator between startLocation: userLocation! and endLocation: coordinates but with some research i saw that i can not launch the navigator in the same view, i need to open the maps application, so i decided to add the MapKit and a button
#IBAction func navigationStart(_ sender: Any) {
}
so how can i do that by pressing the button the map application opens with direction from userLocation to coordinates ? I already looked to similar question but is a little different to my problem, because i already have the points but in different format.
Your question is a little confusing but if you want to open the maps app and show direction from a user's current location to another point on the map then you don't need to pass the user's location, just the destination:
Swift 4:
let coordinate = CLLocationCoordinate2DMake(51.5007, -0.1246)
let placeMark = MKPlacemark(coordinate: coordinate)
let mapItem = MKMapItem(placemark: placeMark)
mapItem.name = "Big Ben"
mapItem.openInMaps(launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving])
Objective C:
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(51.5007, -0.1246);
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate: coordinate];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:#"Big Ben"];
[mapItem openInMapsWithLaunchOptions:#{MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving}];
I have the following code:
func mapView(mapView: GMSMapView, didTap marker: GMSMarker){
let lat: CLLocationDegrees = marker.position.latitude
let lng: CLLocationDegrees = marker.position.longitude
var formattedCoordinate = CLLocationCoordinate2D(latitude: lat,longitude: lng)
markersArray.remove(formattedCoordinate)
self.clean()
}
func mapView(mapView: GMSMapView, didBeginDragging marker: GMSMarker){
let lat: CLLocationDegrees = marker.position.latitude
let lng: CLLocationDegrees = marker.position.longitude
var formattedCoordinate = CLLocationCoordinate2D(latitude: lat,longitude: lng)
markersArray.remove(formattedCoordinate)
}
As you can see I am trying to "remove" the "formattedCoordinate" from markersArray. I saw that there are options like .filter and other methods which enables removing an element at a specific index, but here I would like to remove that specific coordinate from the array. How do I do that?
markers = markers.filter({ (coordinateToRemove) -> Bool in
return coordinateToRemove.latitude == formattedCoordinate.latitude && coordinateToRemove.longitude == formattedCoordinate.longitude
})
I had the same problem solved it by rounding off the values of latitude and longitude(as they can be different by some decimal in formattedCoordinate Object) that you are comparing using
round(coordinateToRemove.latitude)
and comparing them separately.
I am looking to get data from a Firebase Database into a map. I have a good amount working but am stuck. This is all 100% code, no storyboards.
What I have below works. It will show all pins on a map but I am stuck at that point. I want to be able to tap each pin and get the data for that particular pin. When I do, using the code below I will print out "tap" and the array for MTA.
The data could be shown in a pin annotation/info window or in labels below the map in the View Controller. I am unsure of where to put the code/get it to work. I assume not in the for snap in snapshot but I cannot get the data out for each individual record/pin.
View did load for reference:
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
self.navigationItem.title = stop
mapContainerView.delegate = self
view.addSubview(mapContainerView)
setUpContorller()
fetchTrip()
}
Function to get coordinates for map:
func fetchTrip(){
let ref = FIRDatabase.database().reference()
let tripsRef = ref.child("Trips").child(stop!)
tripsRef.observeSingleEvent(of: .value, with: { (snapshot) in
for snap in snapshot.children {
let tripSnap = snap as! FIRDataSnapshot
if let dict = tripSnap.value as? [String:AnyObject] {
let lat = dict["lat"] as! CLLocationDegrees
let lng = dict["lng"] as! CLLocationDegrees
let MTA = dict["MTAStop"] as! String
let center = CLLocationCoordinate2D(latitude: lat, longitude: lng)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.08, longitudeDelta: 0.08))
self.stopMTA.append(MTA)
self.mapContainerView.setRegion(region, animated: true)
let pinCoordinate: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, lng)
let annotation = MKPointAnnotation()
annotation.coordinate = pinCoordinate
self.mapContainerView.addAnnotation(annotation)
}
}
})
}
Function to tap pin: (I know I need more.. not sure what, possibly a class to hold the data.)
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
// do something
print("tap")
print(stopMTA)
}
Here is an example of the database from simulator testing.
Thanks in advance!
Using MKPointAnnotation() will only place a pin on the map. You need to use a custom class to hold the annotation information and call it with initializers.
Original:
let annotation = MKPointAnnotation()
annotation.coordinate = pinCoordinate
self.mapContainerView.addAnnotation(annotation)
Working version:
let annotation = PinAnnotation(title: MTA, coordinate: pinCoordinate, info: MTA)
annotation.coordinate = pinCoordinate
self.mapContainerView.addAnnotation(annotation)
Also Need:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
}
and
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
}