Only allow one pin drop - ios

I have an app and im following a online course to show how to drop pins on the map but that lets you drop an infinite amount of pins. I only want 1 pin to be dropped at a time, for example if you drop a pin at this location then drop a pin at another it removes original pin
Here is my code so far
let longPress = UILongPressGestureRecognizer(target: self, action: "mapLongPress:")
longPress.minimumPressDuration = 2
self.mapView.addGestureRecognizer(longPress)
func mapLongPress(recognizer: UIGestureRecognizer){
print("its done")
let touchedAt = recognizer.locationInView(self.mapView)
let touchedAtCoordinate : CLLocationCoordinate2D = mapView.convertPoint(touchedAt, toCoordinateFromView: self.mapView)
let newPin = MKPointAnnotation()
newPin.coordinate = touchedAtCoordinate
mapView.addAnnotation(newPin)
}

You can remove all annotations before dropping another pin.
mapView.removeAnnotations(mapView.annotations)

Dont create a new pin each time, just update the coordinates for the pin

Not sure if this is the correct way but anytime I need to show a new pin or annotation on the map I clear the old one.
[self.mapView removeAnnotations:[self.mapView annotations]];
Sorry havent got the code in swift but it works for me as I need to show vehicle icon on map and every 30 sec it shows the new position. Hope this helps.

Related

ARkit How to get exact point of node from tap location

I have following code on tap gesture on sceneview
let location = gesture.location(in: self.sceneView)
let hitTestScene = self.sceneView.hitTest(location, options:nil)
if let first = hitTestScene.first {
}
I am able to get node from first
What I want is Suppose I have wall node which is SCNPlane or SCNBox with very big height.
Now If User tap on particular location let say on half of node. I want to that point in that node.
So the question is With sceneView.hitTest I can get node which tapped but I want the location in node. like where that exactly tapped.
So I can measure height from origin to tapped location
Any Suggestion will be appreciated
Okay I found the solution.
We can get position to the hit node with SCNHitTestResult's localCoordinates property
let location = self.centerImage.center
let hitTestScene = self.sceneView.hitTest(location, options:nil)
if let first = hitTestScene.first {
print("localCoordinates in tapped ndoe is" first.localCoordinates )
}
Hope it is helpful to someone

Why is my map view zooming in when I add annotations?

I have a MKMapView that I configure with:
static let STARTING_MAP_RANGE: Double = 1000 // meters
. . .
let region: MKCoordinateRegion = MKCoordinateRegionMakeWithDistance(location,
MapViewController.STARTING_MAP_RANGE,
MapViewController.STARTING_MAP_RANGE)
mapView.setRegion(region, animated: true)
I add an annotation for the current location and it all looks fine. When I add an annotation for other points in the visible region, the MKMapView zooms in to the minimum area needed to show all the annotations.
The weird thing is that I tried to figure out where this was happening by printing out the bottom left and top right latitude and longitude like this:
private func printMapRegion(caller: String)
{
let mapRect = mapView.visibleMapRect;
let bottomLeft = MKCoordinateForMapPoint(MKMapPointMake(mapRect.origin.x, MKMapRectGetMaxY(mapRect)))
let topRight = MKCoordinateForMapPoint(MKMapPointMake(MKMapRectGetMaxX(mapRect), mapRect.origin.y))
print("\(caller): (\(bottomLeft.latitude),\(bottomLeft.longitude)) -- (\(topRight.latitude),\(topRight.longitude))")
}
When I run this before and after setting the annotations, I get identical values, despite seeing the map zoom on the screen (both in the simulator and my iPhone).
I added a refresh button to reset the map. It works as far as zooming the map out, but it also reports that the bottom left and top right coordinates are the same before and after zooming.
Is there something wrong with my understanding of visibleMapRect?
I found that the reason for the zooming is that I was adding the annotations like this:
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotations(annotations)
mapView.showAnnotations(mapView.annotations, animated: true)
Removing the call to showAnnotations eliminated the problem. I'm still curious as to why visibleMapRect is reporting the same bounding coordinates after the visible zoom.

GMSMarker icon in the top left corner of the view (iOS)

I am trying to create a UITableViewCell containing a GMSMapView with a GMSMarker at the center of the current Position.
The problem is that the marker always appears at the top left corner of the current position and I don't know how to solve the problem.
I tried to follow these steps: Implementing a Google Map with UItableviewCell
here is my code from cellForRowAt:
let locationCell = tableView.dequeueReusableCell(withIdentifier: "activityLocationCell") as! ActivityLocationCell
let latitude = CLLocationDegrees(activity.coordinates![0])
let longitude = CLLocationDegrees(activity.coordinates![1])
let position = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
locationCell.googleMapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 15)
let marker = GMSMarker(position: position)
marker.groundAnchor = CGPoint(x: 0.5, y: 0.5)
marker.map = locationCell.googleMapView
return locationCell
Here is a screenshot of my problem:
marker is at the top left corner of the map
I had a pretty similar issue. I resolved it by changing the moment I configure the map in the view lifecycle.
In my case, I was using a child view controller. I was configuring the map before viewWillAppear was called which caused the map to not center properly (the marker was on the top left corner). I moved my call to after the viewWillAppear and it fixed it. A good place would be viewDidAppear.
If you are using a cell, you will probably need to investigate with the view lifecycle instead of the controller lifecycle.
This is not written anywhere on the Google documentation.
you have to draw map in
func viewDidLayoutSubviews()
Try creating Marker when map is ready completely. for eg: use the delegate.
var ifMapReady: Bool = false
...
...
func mapViewSnapshotReady(_ mapView: GMSMapView) {
ifMapReady = true
}
//Call this method from where ever you want to load map
func updateMap() {
if ifMapReady {
//Load Map
}
}
This delegate will be called multiple times(eg: map is swiped or moved etc) whenever the Map tiles are ready. So we can use a boolean value for understanding that map loaded successfully. Based on that value we can load the Map properly when initiating.
I want to add one more thing. #Gabriel Cartier's answer worked for me with one additional change in my code.
[self->mapView_ animateToCameraPosition:camera];
And I replaced with
[self->mapView_ setCamera:camera];

Get center coordinates from MapKit and display in UILabel

I'm developing an iOS app using XCode 7.2 and Swift 2.1, and I've successfully implemented a MapKit map in my app. The map loads perfectly and centers on the user's current location.
Now I want to retrieve the center coordinates should the user move the center of the map to a new location. This new location's coordinates will be "captured" on the press of a button (see the "Set Grid Reference" button in the attached gif) and be displayed in a label.
Move from A to B and set new center coordinates
The closest I've come to an answer is here, and I've implemented that code, but I still can't figure out how to update the label with the coordinates by clicking the IBOutlet button I've created.
What am I missing here?!
Any help would be highly appreciated - thanks in advance!
----------------FOLLOW-ON QUESTION------------------
Now that we've solved the problem and we got the label populated with the new center coordinates, I have one more question - most probably a noob oversight, but I'm on a steep learning curve here, so please bear with me...
We have successfully determined the center coordinates and they are now set as mapLongitude and mapLatitude inside the function we've created.
I have two other variables (newTargetLong and newTargetLat) that forms part of an array of values that will be passed on to the next view controller, and I want to:
let newTargetLong = mapLongitude
let newTargetLat = mapLatitude
so that the new latitude and longitude can be added to the array with an .append instruction.
But for some reason, I just can't get those two values "out" of that function. What do I need to do to accomplish that?
Declare var center = "" at the top of your class with other declarations. In the method below, it should automatically change the value of center:
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
center = mapView.centerCoordinate
}
When you press your button set the value of your label to the value of center.
self.yourLabelName.text = center
To display as "Latitude: ... Longitude: ..." do as follows:
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let mapLatitude = mapView.centerCoordinate.latitude
let mapLongitude = mapView.centerCoordinate.longitude
center = "Latitude: \(mapLatitude) Longitude: \(mapLongitude)"
print(center)
self.yourLabelName.text = center
}
If you want to format the coordinates to display a little more friendly:
center = "\(String(format: "%.5f", mapLatitude)), \(String(format: "%.5f", mapLongitude))"
Adjust the %.5f according to your preference of number of decimal places.
OK, so I got it working with some small alterations to the code that #AppDevGuy provided. Here's what I've done:
func mapView(myMap: MKMapView, regionDidChangeAnimated animated: Bool) {
let center = myMap.centerCoordinate
let mapLatitude = center.latitude
let mapLongitude = center.longitude
let latAndLong = "Lat: \(mapLatitude) \nLong: \(mapLongitude)"
self.TargetGridReference.text = latAndLong
}
And for the button press:
#IBAction func SetTargetGridReference(sender: UIButton) {
return mapView(myMap, regionDidChangeAnimated: true)
}
The output in the UILabel looks like this:
Lat: -34.5678901234567
Long: 19.1234567890123
I'm not sure if this is clunky or elegant, but it works like a charm! I've checked the output and the coordinates are spot on!
One last question arising from this: Is there any way to shorten those values of the latitude and longitude to say 6 digits, instead of the 13 it currently have?
Thanks #AppDevGuy! Sincerely appreciated!
First I am assuming: you are not sure when and where to update the text of the Label(you created)
Then,based your linked post about how to get the current center coordinate,
I think you can try added a line in this fun:
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
var center = mapView.centerCoordinate
#add a line here to update the label
}
Since every time user recenter the map, this delegate func will be called, and the label will automatically updated with current new center coordinate.
To shorten the coordinate use the "%.4f" format. Here is an example of a piece of cord i used for my lat and long with a shortened coordinate, I'm sure you can work out how it works.
myLabel.text = "\(String(format: "%.4f", location.coordinate.latitude)), \(String(format: "%.4f", location.coordinate.longitude))"
This prints the coordinates from my location into one label. the .4 represents the decimal places. so you can choose whatever number you want for how long or short you want the coordinates.

Custom user location dot in Google maps for iOS (GMSMapview)

Is there an official way to set a custom user location dot in Google maps for iOS (GMSMapView)?
Is there a known way to "hack" it? Like iterating through all subviews and layers and fish the blue dot?
Even if you can't customise its appearance, can you control its z order index? When you have many markers, the little blue dot becomes hidden, and sometimes you want it to be visible at all times.
Thanks
You can try to find the image on:
GoogleMaps.framework > Resources > GoogleMaps.bundle
OR
GoogleMaps.framework > Resources > GoogleMaps.bundle > GMSCoreResources.bundle
I did a quick search on those and the only associated file I found with that blue dot is GMSSprites-0-1x.
Please read the google maps terms and conditions because this might not be legal.
You can set the maps myLocationEnabled to NO. That will hide the default location dot. Then use an instance of CLLocationManager to give you your position. Inside CLLocationManager didUpdateLocations method you can set a custom GMSMarker. Set its icon property to whatever you want your dot to look like using [UIImage imageNamed:]. This will allow you to achieve the desired effect.
Swift 4
Disable the default Google Map current location marker (it's disabled by default):
mapView.isMyLocationEnabled = false
Create a marker as an instance property of the view controller (because a delegate will need access to this):
let currentLocationMarker = GMSMarker()
The GMSMarker initializer allows for a UIImage or a UIView as a custom graphic, not a UIImageView unfortunately. If you want more control over the graphic, use a UIView. In your loadView or viewDidLoad (wherever you configured the map), configure the marker and add it to the map:
// configure custom view
let currentLocationMarkerView = UIView()
currentLocationMarkerView.frame.size = CGSize(width: 40, height: 40)
currentLocationMarkerView.layer.cornerRadius = 40 / 4
currentLocationMarkerView.clipsToBounds = true
let currentLocationMarkerImageView = UIImageView(frame: currentLocationMarkerView.bounds)
currentLocationMarkerImageView.contentMode = .scaleAspectFill
currentLocationMarkerImageView.image = UIImage(named: "masterAvatar")
currentLocationMarkerView.addSubview(currentLocationMarkerImageView)
// add custom view to marker
currentLocationMarker.iconView = currentLocationMarkerView
// add marker to map
currentLocationMarker.map = mapView
All that remains is giving the marker a coordinate (initially and every time the user's location changes), which you do through the CLLocationManagerDelegate delegate.
extension MapViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let lastLocation = locations.last!
// update current location marker
currentLocationMarker.position = CLLocationCoordinate2D(latitude: lastLocation.coordinate.latitude, longitude: lastLocation.coordinate.longitude)
}
}
The first few locations that the location manager produces may not be very accurate (although sometimes it is), so expect your custom marker to jump around a bit at first. You can wait until the location manager has gathered a few coordinates before applying it to your custom marker by waiting until locations.count > someNumber but I don't find this approach very attractive.

Resources