Set first annotation in annotations - ios

OK,
I have an array of pubs:
var pubs = [Pub(coordinate: CLLocationCoordinate2D(latitude: 43.2282385, longitude: 76.855085)),
Pub(coordinate: CLLocationCoordinate2D(latitude: 43.2345965, longitude: 76.8907758)).
and I add annotations to my map:
mapView.addAnnotations(pubs).
Then I select first annotation this way:
mapView.selectAnnotation(mapView.annotations.first!, animated: true)
But now it shows first selected annotations, then second.
Question:
How to set the needed annotation first in annotations?
Thanks.

Howe said #ogres: mapView might re-arrange the array of the Pubs, so i had to select it from the TableView-s array mapView.selectAnnotation(tableView.annotations.first!, animated: true)

Related

Mapbox iOS - Show multiple callouts

I want to show multiple annotations at once in Mapbox (note: NOT MKMap). There doesn't seem to be a method to show multiple annotations, although it can add multiples.
e.g.
mapView.addAnnotations(<annotationsArray>)
Even though there is a method as follows, it does not show the annotations.
mapView.showAnnotations(<annotationsArray>, animated: true)
What I want it to show multiple instances as shown in the image below. i.e. I want to show several "Hello World" annotations in the map, for each point the user added.
Is there a similar method in Mapbox to show multiple annotations in Swift?
Use this to display multiple annotations:
func setAnnotations() {
var index = 0
for placeModel in self.placesList! {
let marker = MyMGLPointAnnotation()
marker.willUseImage = true
marker.id = placeModel.id
marker.type = placeModel.type
if let img = placeModel.images.first {
marker.imgURL = img.thumbnail
}
marker.coordinate = CLLocationCoordinate2D(latitude: placeModel.location?.latitude ?? 0, longitude: placeModel.location?.longitude ?? 0)
marker.title = placeModel.name.withoutHtmlTags
marker.subtitle = placeModel.descr.htmlToString
//DispatchQueue.main.async {
self.mapView.setCenter(CLLocationCoordinate2D(latitude: latitude, longitude: longitude), zoomLevel: 12, animated: false)
self.mapView.addAnnotation(marker)
}
}
You can display multiple instance of the annotations but for the selection you can tap one by one and it will show title like the image you shared.
Edit: There is way you can create your custom xib load as annotation to show the title.
Check: https://github.com/mapbox/ios-sdk-examples/blob/0e2c8ce878de500f36c4168f7a1e62041c8adbdf/Examples/Swift/AnnotationViewsAndImagesExample.swift
https://docs.mapbox.com/ios/maps/examples/annotation-view-image/

Creating a constant from properities returned from arrays

Basically I have two arrays one containing latitudes and the other containing longitudes (the real arrays are much longer obviously).
i.e:
latArray = [50.456782, 57.678654]
longArray = [14.578002, 17.890652]
I need to go trough these arrays with a for loop and create an object that would have respective latitude and longitude depending in order of the array. However I don't really know how to go about it.
i.e.
firstPlace.latitude = 50.456782
firstPlace.longitude = 14.578002
secondPlace.latitude = 57.678654
secondPlace.longitude = 17.890652
I need these as separate variables, because I need to pass them into MKAnnotation so that they can be later represented in an MKAnnotationView as various locations on the map.
Hopefully this is clear enough, any help is appreciated.
Thanks.
It would likely be better to use CLLocationCoordinate2D from the CoreLocation framework to represent a coordinate location.
This sounds like a good place to use the zip command.
Here is an example:
let latArray = [50.456782, 57.678654]
let longArray = [14.578002, 17.890652]
let coordinates = zip(latArray, longArray).map { lat, lon in
CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
print(coordinates)
Output (tidied slightly):
[CLLocationCoordinate2D(latitude: 50.456781999999997, longitude: 14.578002), CLLocationCoordinate2D(latitude: 57.678654000000002, longitude: 17.890651999999999)]
MKAnnotation uses a CLLocationCoordinate2D for it's coordinate property anyway, so this should be easier. You could even create your MKAnnotations in the map function if you wanted.
Example of using with a struct:
let latArray = [50.456782, 57.678654]
let longArray = [14.578002, 17.890652]
struct Place {
var name: String
var coordinate: CLLocationCoordinate2D
}
let places = zip(latArray, longArray).map { lat, lon in
Place(name: "Some place",
coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lon))
}
print(places)

Change MKMapView's Zoom - Swift 4

I using Apple's MapKit and MKMapView to show a location on screen. The function I am using is:
func displayLocation() {
locationMap.setRegion(MKCoordinateRegion(center: CLLocationCoordinate2DMake(userConnected.siteConnectedLat!, userConnected.siteConnectedLong!), span: MKCoordinateSpanMake(0.05, 0.05)), animated: true)
let locationPin = CLLocationCoordinate2D(latitude: userConnected.siteConnectedLat!, longitude: userConnected.siteConnectedLong!)
let annotation = MKPointAnnotation()
annotation.coordinate = locationPin
locationMap.addAnnotation(annotation)
locationMap.showAnnotations([annotation], animated: true)
}
Is is then called in the viewDidLoad method of the View Controller. Apple's documentation says that the span should change the zoom but even changing the span is putting minimum effect on the map. I want it to be zoomed out enough so that we can clearly see like 3-4 European countries, i.e, a significant amount of zoom-out.
This is what my map looks like in simulator:
This is how it looks like after I press enlarge:
You need to set the region of the map in viewDidAppear, not viewDidLoad. When viewDidLoad is called, the map view has just been loaded - the map hasn't been rendered yet, so you can't set its region.
Another thing to change is the span. (0.05, 0.05) seems too small a span to show 3-4 countries. You should try something bigger, like (5, 5). Remember that these numbers represent in degrees the width and height of the map region.

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.

Resources