Get Location From Center of Screen Swift MapKit - swift

I'm new on Swift Programming, and I'm trying to build an app that I can get the coordinates of the center of the view with MapKit and Swift 2.
I already can get the current location, but I need if I move on the map, the location set to the new point which will be the center of the screen.
Can you help me with this please?.
Regards,

You can use the regionDidChangeAnimated delegate method and call mapView.centerCoordinate. It will look like the following:
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
var center = mapView.centerCoordinate
}
Also make sure that your Class is extending MKMapViewDelegate and you are calling
self.mapView.delegate = self in your viewDidLoad() function.

Related

Hide Google Map info window when map is moved with Swift

So with my app, I'm displaying a custom info window on a GMS Marker. This info window takes up the top half of the screen and I don't want it moving with the Marker. So I want to hide the info window as soon as the map has moved. How can I do this?
You could make your UIViewController conform to GMSMapViewDelegate and then implement one of the methods listed here: https://developers.google.com/maps/documentation/ios-sdk/reference/protocol_g_m_s_map_view_delegate-p
I guess the first one (mapView:willMove:) would work for you. I would use a print statement (or breakpoint) to check, whether the method is triggered as expected. To hide the current info window, you should be able to set mapView.selectedMarker = nil.
To sum up, your code might look like this:
import UIKit
import GoogleMaps
class ViewController: UIViewController {
//declare your map, etc.
override func viewDidLoad() {
super.viewDidLoad()
// setup your map
}
}
extension ViewController: GMSMapViewDelegate {
func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
if gesture { //The map was moved by the user
//mapView.selectedMarker = nil
}
}
}

Calling mapView(_:viewFor:) when user location changes

I want to have the user location being shown as a custom image (not the blue beacon). I also want that whenever the user location changes its coordinates, this custom image is rotated accordingly to represent the user course. In order to achieve that, I implemented the code below. It is being called with annotation type userLocation when the app is started, so that the user location custom image is being shown fine. The problem is that when I simulate a change in user location coordinates, the delegate mapView(_:viewFor:) method is never called again with an annotation type userLocation, so the image is never rotated. (Note: the UIImage rotateImage(by:) is a custom method).
Is there some means to call mapView(_:viewFor:) so that I can update the image annotation for user location when user location changes? Thanks for any help.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.isEqual(mapView.userLocation) {
// Annotation image for user location
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
annotationView.image = UIImage(named: "UserLocationImage.png")?.rotateImage(by: currentCourse)
return annotationView
}
}
Use CLLocationManagerDelegate
https://developer.apple.com/documentation/corelocation/cllocationmanagerdelegate
Implement this protocol in your code, and put your mapView function into its locationManager(_:didUpdateLocations:) method.

Implementing gesture on a marker.iconView in swift 3 and google maps for ios

I've got a google map and i'm setting marker.iconView to a custom UIView.
marker.iconView = customUIView()
func customUIView()-> UIView
{
var theView:UIView
theView.isUserInteractionEnabled = true
let gesture = UITapGestureRecognizer(target: self, action:
#selector (self.popAction(sender:)))
theView.addGestureRecognizer(gesture)
}
The UIView is pretty much just a textbox and when the UIView is clicked I won't a popup happening from popAction.
But I can't get the gesture functionality to work and I wonder if it's because the gesture is being registered on the google map and not on the UIView.
**** Update *****
After reading the google docs i'm pretty sure i can't add a gesture to a marker.iconView because the UIView is just a "snapshot"
Instead i'm implementing GMSMapViewDelegate.
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print("markerTapped")
return true
}
This function works but what i'd like to do is pass data from my UIView that is the marker.iconView into the above func mapView and not entirely sure how.
update
So marker.iconView = customUIView(sport: sportEvent) and each sportEvent object has title, date and description. The customUIView looks like a textbox with the info.
There is a loop through an array so that each marker on the map has specific sportEvent info.
Ideally, I'd like to add a gesture to the customUIView so that when the "marker" is clicked an alert pops up with the details of sportEvent title, date and description. But the way google renders marker.iconView means user input is lost from the customUIView so I can't set a gesture on it.
So i'm looking for a workaround where I can get a particular marker clicked and then an alert pops with that sportEvent info.
So I used GMSMapViewDelegate and then when the marker is clicked func mapView fires. That's cool but I can't get the sportEvent info associated with each particular marker.
So I tried to pass the sportEvent object into func mapView but then the function doesn't seem to execute and the marker is no longer clickable.
Thx.
The way I approached it was creating a custom GMSMarker. This will create the points on your mapView.
You want to pass in your sportEvent object when initializing the custom marker (i.e. something like CustomMarker(with: sportEvent))
The GMSMarker object has some properties you can set which you can find here but, some of the notable ones include:
title, snippet (text beneath title) which is what you want to set from your sportEvent object.
So, in your custom marker you can do:
Class CustomMarker: GMSMarker {
var title: String
var desc: String
...
init(with sportEvent: SportEvent) {
// do some validation before setting this assumes all values are set correctly
self.title = sportEvent.title //(assuming `.title` is a string)
self.desc = sportEvent.description
...
super.init()
title = self.title
snippet = self.desc
}
}
Note that the custom GMSMarker may need a position property set which is just a CLLocationCoordinate2D i.e. (position = CLLocationCoordinate2D(latitude: sportEvent.latitude, longitude: sportEvent.longitude)
This will by default show you a mini marker info window with your sportEvent object.
If you want to further customize the marker info window you can take a look at markerInfoWindow
It returns a view if it exists. What I did was create my view programatically and I passed in my custom marker into the view and set everything accordingly there.
Like so:
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
let customMarker = marker as! CustomMarker
return myCustomView(with: customMarker)
}
Where myCustomView is a method that returns a UIView`
func myCustomView(with customMarker: CustomMarker) -> UIView {
// Set view programatically here with your customMarker
}
Hope it helps!

Get LAT and LONG from tapped overlay in Google Maps

When a user taps an overlay, the following code is triggered:
func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay) {
}
I wonder if we can extract the exact LAT and LONG coordinates of the overlay that has been tapped?
Thanks!
To solve this we need the 2 methods together,
So I combined them in a way I hope it will help in this issue:
func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay) {
print(overlay)
}
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
print(coordinate)
for polyline in polylines {
if GMSGeometryIsLocationOnPath(coordinate, polyline.path!, true) {
self.mapView(mapView, didTap: polyline)
}
}
for polygon in polygons {
if GMSGeometryContainsLocation(coordinate, polygon.path!, true) {
self.mapView(mapView, didTap: polygon)
}
}
}
if the user clicked at coordinate we will deal with this, Then check if this coordinate is contained in any Polyline or Polygon we had defined before, So we fire the event didTap overlay for that overlay.
Make sure to make polylines and polygons isTappable = false
And but in mind this event will be fired for every overlay tapped even though if they are overlaped, You can put return when the if success to take the first overlay only
You can use didTapAt delegate method for the same.
#wajih, for you did the method didTapAt was called when you tap on landmark names or titles? For me it's not getting called.
For my case the landmark title is above the polygon and the didTapAt method is not getting called, but if i set tappable to true then didTap(overlay) is called perfectly.
If you just want to get the exact coordinates wherever you tapped whether on Overlay or not, then there is another delegate of GMSMapViewDelegate which is called whenever we tap on GoogleMaps. In this delegate you can get the exact coordinates where you tapped on map irrespective of tapping on an overlay.
Swift 3.0
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
print(coordinate.latitude)
print(coordinate.longitude)
}
If you want to get the coordinate only on tapping marker, then use this delegate method
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print(marker.position.latitude)
print(marker.position.longitude)
return true
}
Make sure to make your overlay as non-tappable
overlay.isTappable = false
For reference see here

How to let a textfield hover/float above a mapView

I'm making an app which uses MapView, now I've positioned the textfield above the mapview, like on the image. But I really want to fullscreen the mapview and let a textfield float/hover above it. Does anybody know how I can make something like that? I have searched a lot on the internet but couldn't find any clue.. Hope someone can get me starting.
Right, presumably your map view is pinned on all four sides to its superview? Setup your constraints as follows, not how the mapview is not pinned to the text field, but the superview.
http://imgur.com/a/8YmXL
To add the drop shadow, set the following properties on your UITextField:
textField.layer.shadowOpacity = 1.0
textField.layer.shadowRadius = 0.0
textField.layer.shadowColor = UIColor.blackColor().CGColor
textField.layer.shadowOffset = CGSizeMake(0.0, -1.0)
Adjust the settings until you are happy with the look of the shadow.
To dismiss the keyboard when the user pans around the map is very simple. You just need to implement the delegate. Edit your class to look a bit like this:
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet var mapView: MKMapView!
#IBOutlet var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
textField.resignFirstResponder()
}
}