iOS | Tapping on Marker Zooms out Google Map SDK - ios

I have a GMSMapView instance, orderMapView, which is linked to my UIViewController. I give Location Permissions and later make self as delegate of orderMapView
orderMapView.delegate = self
I also make the class conform to GMSMapViewDelegate. I then initiate multiple markers in viewDidLoad, one of which is like this:
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: CLLocationDegrees(dataLat), longitude: CLLocationDegrees(dataLng))
marker.title = dataName
marker.snippet = "LAT: \(dataLat), LONG: \(dataLng)"
marker.appearAnimation = .pop
marker.map = orderMapView
marker.isDraggable = true
marker.isTappable = true
I also implement the following delegate methods:
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D){
//1 - IT NEITHER COMES HERE
print(coordinate)
}
func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
print(position)
}
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
//2 - IT NEITHER COMES HERE
orderMapView.selectedMarker = marker
return true
}
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
let view = UIView(frame: CGRect.init(x: 0, y: 0, width: 200, height: 70))
view.backgroundColor = UIColor.white
view.layer.cornerRadius = 6
let lbl1 = UILabel(frame: CGRect.init(x: 8, y: 8, width: view.frame.size.width - 16, height: 15))
lbl1.text = marker.title
view.addSubview(lbl1)
let lbl2 = UILabel(frame: CGRect.init(x: lbl1.frame.origin.x, y: lbl1.frame.origin.y + lbl1.frame.size.height + 3, width: view.frame.size.width - 16, height: 15))
lbl2.text = marker.snippet
lbl2.font = UIFont.systemFont(ofSize: 14, weight: .light)
view.addSubview(lbl2)
return view
}
I can see the markers on the map but when I tap it, the map zooms out and never shows the info windows on those markers. Please help.
UPDATE: This is happening on Simulator as I don't have a device. Can that be the sore and sole problem?

Related

swift GMSMap markerInfoWindow show by animation

i want to show my markInfoWindow when i tap the marker from red to blue
i tried this
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
let windowInfoView: UIView = {
let view = UIView(frame: CGRect.init(x: 0, y: 0, width: 130, height: 55))
view.backgroundColor = UIColor.white
view.layer.cornerRadius = view.frame.height/3
return view
}()
let anim : CABasicAnimation = CABasicAnimation(keyPath: "backgroundColor")
anim.fromValue = UIColor.yellow.cgColor
anim.toValue = UIColor.red.cgColor
anim.duration = 2.0
windowInfoView.layer.add(anim, forKey: "backgroundColor")
return windowInfoView
but when i tap marker, it show yellow window direct, didn't show from yellow to red in 2 sec
thanks
i solved this problem
i created a custom view and add view in delegate
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
self.view.addSubview(self.infoWindow)
UIView.transition(with: self.view, duration: 1, options: [.transitionCrossDissolve], animations: {
self.infoWindow.alpha = 1
}, completion: nil)
return false
}
can't custom view in markerInfoWindow because it return a UIView.

MapView annotation showing image and title

I am developing an app in which I should present MapView annotations showing an image and a title. The following View Controller Swift code shows a default pin image with the desired title right below:
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
// Define zoom
let deltaLat: CLLocationDegrees = 1.0
let deltaLon: CLLocationDegrees = 1.0
// Define location of center coordinates
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(-15.3, -47.0)
// Define area to be viwed
let areaVisual: MKCoordinateSpan = MKCoordinateSpanMake(deltaLat, deltaLon)
let region = MKCoordinateRegionMake(location, areaVisual)
let annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "SDKP"
mapView.addAnnotation(annotation)
// Show map region defined by the above parameters
mapView.setRegion(region, animated: true)
}
/*
// Show an image for annotation
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
annotationView.image = imageLiteral(resourceName: "AnnotationImage")
return annotationView
}
*/
}
This is the MapView I get with this:
When I un-comment the view for annotation method, I get the desired annotation image, but not the title:
Any ideas on how can I get both the image and title at the same time for the annotation?
I found a solution in which I use the func imageFromLabel(_:) in code below to extend UIImage to create an image from a label text which is the title for the annotation. Then I combine the annotation image with this title image through the func combineImageAndTitle(_:_:). Finally, this combined image is showed by the mapView delegate method viewFor annotation.
Since I am still a beginner with Swift, I am not sure if it is the best way to do that. But this solution is working fine for me.
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
// Define zoom
let deltaLat: CLLocationDegrees = 1.0
let deltaLon: CLLocationDegrees = 1.0
// Define location of center coordinates
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(-15.3, -47.0)
// Define area to be viwed
let areaVisual: MKCoordinateSpan = MKCoordinateSpan(latitudeDelta: deltaLat, longitudeDelta: deltaLon)
let region = MKCoordinateRegion(center: location, span: areaVisual)
let annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "SDKP"
mapView.addAnnotation(annotation)
// Show map region defined by the above parameters
mapView.setRegion(region, animated: true)
}
// Delegate method for mapView
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
let imageForAnnotation = #imageLiteral(resourceName: "BaseImage")
let annotationTitle = (annotation.title ?? "") ?? ""
//annotationView.image = imageForAnnotation
annotationView.image = combineImageAndTitle(image: imageForAnnotation, title: annotationTitle)
return annotationView
}
/// Combine image and title in one image.
func combineImageAndTitle(image: UIImage, title: String) -> UIImage {
// Create an image from ident text
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
label.numberOfLines = 1
label.textAlignment = .center
label.textColor = UIColor.black
label.text = title
let titleImage = UIImage.imageFromLabel(label: label)
// Resulting image has a 100 by 100 size
let contextSize = CGSize(width: 100, height: 100)
UIGraphicsBeginImageContextWithOptions(contextSize, false, UIScreen.main.scale)
let rect1 = CGRect(x: 50 - Int(image.size.width / 2), y: 50 - Int(image.size.height / 2), width: Int(image.size.width), height: Int(image.size.height))
image.draw(in: rect1)
let rect2 = CGRect(x: 0, y: 53 + Int(image.size.height / 2), width: Int(titleImage.size.width), height: Int(titleImage.size.height))
titleImage.draw(in: rect2)
let combinedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return combinedImage!
}
}
extension UIImage {
/// Convert a label to an image
class func imageFromLabel(label: UILabel) -> UIImage {
UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0.0)
label.layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
}
And this is the resulting MapView.
You can use MKMarkerAnnotationView and glyphImage property. Try the following code
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: nil)
annotationView.glyphImage = UIImage(named: "Laugh")
return annotationView
}

Google maps GMSMarker changes camera focus iOS

I am having an issue that GMSMarker changes camera focus on any kind of popup alert or whenever I tap on marker and app navigates to google maps application. Following is my implementation. I add google maps container to my viewcontroller header in layoutsubviews method. No idea what's going on. Kindly help.
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
if mapView == nil
{
let camera = GMSCameraPosition.camera(withLatitude: 45.582045, longitude:74.32937, zoom: 14.0)
mapView = GMSMapView.map(withFrame: CGRect(x: 0, y: 0, width: self.mapContainerView.bounds.size.width, height: self.mapContainerView.bounds.size.height), camera: camera)
mapView.delegate = self
do {
// Set the map style by passing the URL of the local file.
if let styleURL = Bundle.main.url(forResource: "style", withExtension: "json") {
mapView.mapStyle = try GMSMapStyle(contentsOfFileURL: styleURL)
} else {
NSLog("Unable to find style.json")
}
} catch {
NSLog("One or more of the map styles failed to load. \(error)")
}
self.mapContainerView.addSubview(mapView)
mapView.settings.setAllGesturesEnabled(false)
let marker = AppointmentMapDataManager(mapView: mapView).setAppointmentMarker()
// let location = GMSCameraPosition.camera(withLatitude: marker.position.latitude,
// longitude: marker.position.longitude,
// zoom: 14)
// mapView.camera = location
var bounds = GMSCoordinateBounds()
bounds = bounds.includingCoordinate((marker as AnyObject).position)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsets(top: self.mapContainerView.frame.height/2 - 33, left: self.mapContainerView.frame.width/2 - 81, bottom: 0, right: 0))
mapView.moveCamera(update)
}
}
Instead of move your camera in the viewDidLayoutSubView which is a wrong approach use didTap method of the GMSMapViewDelegate or if you want to do it automatically use a execute after delay
//method for center camera based in your own code
func centerInMarker(marker: GMSMarker) {
var bounds = GMSCoordinateBounds()
bounds = bounds.includingCoordinate((marker as AnyObject).position)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsets(top: (self.mapView?.frame.height)!/2 - 33, left: (self.mapView?.frame.width)!/2 - 81, bottom: 0, right: 0))
mapView?.moveCamera(update)
}
You can use it in the delegate method
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
self.centerInMarker(marker: marker)
return true
}
Or simply when you add your marker, with delay
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.centerInMarker(marker: marker)
}
You should add in viewDidLoad method, and update frame in viewDidLayoutSubviews.

Cannot constantly update location on iOS xcode project

I am trying to create a mock up app that shows the campus of my school. I want to be able to search through the campus and then click the location button to have the screen follow my location. Check video below to understand my issue. My code is proprietary as i am brand new to swift and xcode. I am not using the story board, just programatically creating this app. When i do get the location to consistently update my location and follow my simulation location, it tears down the view and rebuilds it, which leads to it looking very glitchy. Also, i cannot break the update by changing moving the camera somewhere else. Im sure im missing something quite big. To make as much sense as possible, i want to be able to follow the location on screen in a smooth look, as well as stop the updating location so that can search the campus without my screen updating to my current location.
video link: [https://www.dropbox.com/s/op2kw9sfk0c8dm5/Xcode%20problem.mp4?dl=0][1]
here is my code:
import UIKit
import GoogleMaps
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate{
lazy var mapView = GMSMapView()
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
GMSServices.provideAPIKey("AIzaSyBXEZf5gq-ewIjmlzyWlsDHJSsOTsHCm4k")
let camera = GMSCameraPosition.camera(withLatitude: 35.046462, longitude: -85.298153, zoom: 15.8, bearing: 295, viewingAngle: 0)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.mapType = .satellite
//view = mapView
//User Location
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
locationManager.stopUpdatingLocation()
view = mapView
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: 15.8, bearing: 295, viewingAngle: 0)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.mapType = .satellite
mapView.isMyLocationEnabled = true
mapView.settings.myLocationButton = true
showMarker(position: CLLocationCoordinate2D.init(latitude: 35.046462, longitude: -85.298153), markerTitle: "Cardiac Hill", markerSnippet: "UTC")
showMarker(position: CLLocationCoordinate2D.init(latitude: 35.047488, longitude: -85.300121), markerTitle: "Library", markerSnippet: "UTC")
view = mapView
}
func showMarker(position: CLLocationCoordinate2D, markerTitle: String, markerSnippet: String){
let marker = GMSMarker()
marker.position = position
marker.title = "\(markerTitle)"
marker.snippet = "\(markerSnippet)"
marker.tracksViewChanges = true
marker.opacity = 0.75
marker.icon = GMSMarker.markerImage(with: .white)
marker.map = mapView
}
func markerInfo(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
var view = UIView(frame: CGRect.init(x: 0, y: 0, width: 200, height: 70))
view.backgroundColor = UIColor.white
view.layer.cornerRadius = 6
let lbl1 = UILabel(frame: CGRect.init(x: 8, y: 8, width: view.frame.size.width - 16, height: 15))
lbl1.text = "Cardiac label"
view.addSubview(lbl1)
let lbl2 = UILabel(frame: CGRect.init(x: lbl1.frame.origin.x, y: lbl1.frame.origin.y + lbl1.frame.origin.y + 3, width: view.frame.size.width - 16, height: 15))
lbl1.text = "lbl2 info"
view.addSubview(lbl2)
return view
}
}
Thank you for your time, I will be sure to check this almost everyday to respond to any addition information needed. PS, i already did api and sdk importing, as well as added info into info.plist. I seem to get everything to work but this issue.

Add a label on MGLPolygon

I have a situation where I need to draw an MGLPolygon on a map(MapBox) and I also want to give a UILabel like text on the polygon. The label has to be at the centroid of the polygon and it should be always visible. I found a code with which I can find the centroid of a given polygon, But I couldn't add a label to polygon. I have done the coding in SWIFT so swift developers please help me. Thanks in advance and Happy Coding :)
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
if let currentAnnotation = annotation as? AreaAnnotation {
let reuseIdentifier = currentAnnotation.areaTitle
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier!)
if annotationView == nil {
annotationView = MGLAnnotationView(reuseIdentifier: reuseIdentifier)
annotationView?.frame = CGRect(x: 0, y: 0, width: 120, height: 90)
annotationView!.backgroundColor = UIColor.clear
let detailsLabel:UILabel = UILabel()
detailsLabel.frame = CGRect(x: 30, y: 60, width: 60, height: 25)
detailsLabel.textAlignment = .center
detailsLabel.text = currentAnnotation.areaTitle
// detailsLabel.textColor = UIColor(red:175/255 ,green:255/255, blue:255/255 , alpha:0.75)
detailsLabel.textColor = UIColor.white
detailsLabel.font = UIFont(name: "HelveticaNeue-CondensedBlack", size: 15)
let strokeTextAttributes = [NSAttributedStringKey.strokeColor : UIColor.black, NSAttributedStringKey.strokeWidth : -5.0,] as [NSAttributedStringKey : Any]
detailsLabel.attributedText = NSAttributedString(string: titleLabel.text!, attributes: strokeTextAttributes)
detailsLabel.backgroundColor = UIColor.black.withAlphaComponent(1.0)
detailsLabel.clipsToBounds = true
detailsLabel.layer.cornerRadius = 5.0
detailsLabel.layer.borderWidth = 2.0
detailsLabel.layer.borderColor = UIColor.white.cgColor
annotationView?.addSubview(detailsLabel)
}
return annotationView
}
return nil
}
Thanks #jmkiley but I wanted to clear out that issue as fast as possible so I used this tweak, which was the exact thing I wanted.
If you have the center point of the polygon, you could use it to create a MGLPointFeature. Then create a MGLShapeSource and MGLSymbolStyleLayer with it. Provide the text to that layer. For example:
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate {
var mapView : MGLMapView!
var line: MGLPolyline?
override func viewDidLoad() {
super.viewDidLoad()
mapView = MGLMapView(frame: view.bounds)
view.addSubview(mapView)
mapView.delegate = self
let coords = [
CLLocationCoordinate2D(latitude: 38.0654, longitude: -88.8135),
CLLocationCoordinate2D(latitude: 41.7549, longitude: -88.8135),
CLLocationCoordinate2D(latitude: 41.7549, longitude: -83.1226),
CLLocationCoordinate2D(latitude: 38.0654, longitude: -83.1226)
]
let polygon = MGLPolygon(coordinates: coords, count: UInt(coords.count))
mapView.addAnnotation(polygon)
}
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
let point = MGLPointFeature()
point.coordinate = CLLocationCoordinate2D(latitude: 40.0781, longitude: -85.6714)
let source = MGLShapeSource(identifier: "point-source", features: [point], options: nil)
style.addSource(source)
let layer = MGLSymbolStyleLayer(identifier: "point-layer", source: source)
layer.text = MGLStyleValue(rawValue: "Polygon A")
style.addLayer(layer)
}
}

Resources