I was reading the documentation of Google maps for swift , but compared with Android, I didn't find a way to set the 'Zoom Controls' on my map and by default are disabled.
Exist a way with the Google Maps iOS SDK to display the controls?
I think #Scriptable is right, the documentation hasn't a section for Zoom Controls for iOS SDK.
Well, I made my own (and very basic) controls.
Keep this order (MapView, Button, Button), else, you can't see the buttons.
First one, you must select your UIVIew and change the class to GSMMapView
and, in the MapViewController
import Foundation
import UIKit
import GoogleMaps
class MapViewController: UIViewController {
struct Place {
let id: Int
let name: String
let lat: CLLocationDegrees
let lng: CLLocationDegrees
let icon: String
}
#IBOutlet weak var mapView: GMSMapView!
var markerDict: [Int: GMSMarker] = [:]
var zoom: Float = 15
override func viewDidLoad() {
super.viewDidLoad()
let camera = GMSCameraPosition.camera(withLatitude: 34.1381168, longitude: -118.3555723, zoom: zoom)
self.mapView.camera = camera
do {
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)")
}
let places = [
Place(id: 0, name: "MrMins", lat: 34.1331168, lng: -118.3550723, icon: "i01"),
]
for place in places {
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: place.lat, longitude: place.lng)
marker.title = place.name
marker.snippet = "Custom snipet message \(place.name)"
marker.appearAnimation = kGMSMarkerAnimationPop
//marker.icon = self.imageWithImage(image: UIImage(named: place.icon)!, scaledToSize: CGSize(width: 35.0, height: 35.0))
marker.map = self.mapView
markerDict[place.id] = marker
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnZoomIn(_ sender: Any) {
zoom = zoom + 1
self.mapView.animate(toZoom: zoom)
}
#IBAction func btnZoomOut(_ sender: Any) {
zoom = zoom - 1
self.mapView.animate(toZoom: zoom)
}
}
You should catch current value of zoom, because If you hardcode zoom value and user will use not only buttons but buttons and gestures when user will pressed on button after zoom out by gestures you will zoom to old zoom value (very close to map)
to fix this moment you should catch zoom value here (in GMSMapViewDelegate)
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
zoom = mapView.camera.zoom
}
all code will be looks like this
class A: UIViewController {
var zoom: Float = 15
#IBAction func ZoomInButtonPressed(_ sender: UIButton) {
let nextZoom = zoom + 1
mapView.animate(toZoom: nextZoom)
}
}
extension A: GMSMapViewDelegate {
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
zoom = mapView.camera.zoom
}
}
Related
I'm trying to show my custom view on click of pin in google map. I have mad my custom view for it in xib file and call that file in the delegate method of func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool { But when i run the app and tap the marker it does not show my view. How can i show this? This is my code for custom Xib file,
class MapMarkerWindow: UIView {
#IBOutlet weak var saloonImage: UIImageView!
#IBOutlet weak var nameLbl: UILabel!
#IBOutlet weak var addressLbl: UILabel!
#IBOutlet weak var descriptionLbl: UILabel!
var spotData: NSDictionary?
class func instanceFromNib() -> UIView {
return UINib(nibName: "MapMarkerWindowView", bundle: nil).instantiate(withOwner: self, options: nil).first as! UIView
}
}
This is the code in my VC where i'm showing my map,
#IBOutlet weak var customView: UIView!
var mapView : GMSMapView?
var locationManager = CLLocationManager()
private var infoWindow = MapMarkerWindow()
fileprivate var locationMarker : GMSMarker? = GMSMarker()
override func viewDidLoad() {
super.viewDidLoad()
self.infoWindow = loadNiB()
GMSServices.provideAPIKey("AIzaSyBMppjEPlRBHUD4To2KqNLgmhu1QcxHg3g")
let camera = GMSCameraPosition.camera(withLatitude: 31.516331, longitude: 74.342792, zoom: 6)
mapView = GMSMapView.map(withFrame: .zero, camera: camera)
view = mapView
let states = [
State(name: "Hafeez Center", long: 74.342792, lat: 31.516331, snippets: "Lahore"),
State(name: "Kalma Chowk", long: 74.331553, lat: 31.504532, snippets: "Lahore"),
// the other 51 states here...
]
for state in states {
let state_marker = GMSMarker()
state_marker.position = CLLocationCoordinate2D(latitude: state.lat, longitude: state.long)
state_marker.title = state.name
state_marker.snippet = "Hey, this is \(state.snippets)"
state_marker.map = mapView
}
self.mapView?.isMyLocationEnabled = true
//Location Manager code to fetch current location
self.locationManager.delegate = self
self.locationManager.startUpdatingLocation()
}
func loadNiB() -> MapMarkerWindow {
let infoWindow = MapMarkerWindow.instanceFromNib() as! MapMarkerWindow
return infoWindow
}
//Location Manager delegates
private func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let camera = GMSCameraPosition.camera(withLatitude: (location?.coordinate.latitude)!, longitude: (location?.coordinate.longitude)!, zoom: 17.0)
self.mapView?.animate(to: camera)
//Finally stop updating location otherwise it will come again and again in this delegate
self.locationManager.stopUpdatingLocation()
}
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
var markerData : NSDictionary?
if let data = marker.userData! as? NSDictionary {
markerData = data
}
locationMarker = marker
infoWindow.removeFromSuperview()
infoWindow = loadNiB()
guard let location = locationMarker?.position else {
print("locationMarker is nil")
return false
}
// Pass the spot data to the info window, and set its delegate to self
infoWindow.spotData = markerData
//infoWindow.delegate = self
// Configure UI properties of info window
infoWindow.alpha = 0.9
infoWindow.layer.cornerRadius = 12
infoWindow.layer.borderWidth = 2
//infoWindow.infoButton.layer.cornerRadius = infoWindow.infoButton.frame.height / 2
let saloonImage = markerData!["image"]!
let name = markerData!["name"]!
let address = markerData!["address"]!
let description = markerData!["description"]!
infoWindow.addressLbl.text = address as? String
infoWindow.nameLbl.text = name as? String
infoWindow.descriptionLbl.text = description as? String
infoWindow.saloonImage.image = saloonImage as? UIImage
//Offset the info window to be directly above the tapped marker
infoWindow.center = mapView.projection.point(for: location)
infoWindow.center.y = infoWindow.center.y - 82
self.view.addSubview(infoWindow)
return false
}
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
if (locationMarker != nil){
guard let location = locationMarker?.position else {
print("locationMarker is nil")
return
}
infoWindow.center = mapView.projection.point(for: location)
infoWindow.center.y = infoWindow.center.y - 82
}
}
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
infoWindow.removeFromSuperview()
}
This is how my pin looks when i tap on it.
From your code it seems that there is a problem in loading Nib.
Please check below code.
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
self.tappedmarker = marker
var point = mapView.projection.point(for: marker.position)
point.y = point.y - 110
let camera = mapView.projection.coordinate(for: point)
let position = GMSCameraUpdate.setTarget(camera)
mapView.animate(with: position)
self.customMarker = CustomMarker.instancefromNib() as! CustomMarker
customMarker.layer.cornerRadius = 10.0
customMarker.clipsToBounds = true
self.customMarker.center = mapView.projection.point(for: marker.position)
self.customMarker.center.y = self.customMarker.center.y - 110
self.view.addSubview(self.customMarker)
self.customMarker.bringSubview(toFront: self.view)
return true
}
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
if (tappedmarker != nil) {
guard let location = tappedmarker?.position else {
print("locationMarker is nil")
return
}
customMarker.center = mapView.projection.point(for: location)
customMarker.center.y = customMarker.center.y - 100
}
}
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
if self.view.subviews .contains(self.customMarker) {
self.customMarker.removeFromSuperview()
return
}
}
Here is the instancefromNib :
class CustomMarker: UIView {
#IBOutlet weak var lblTitle: UILabel!
class func instancefromNib() -> UIView {
return UINib.init(nibName: "CustomMarker", bundle: nil).instantiate(withOwner: self, options: nil).first as! UIView
}
}
This will look like this :
Hope this will help!
Just set your mapView delegate in viewDidLoad()
self.mapView.delegate = self
https://developers.google.com/maps/documentation/ios-sdk/utility/marker-clustering
I am working for map clustering . In map clustering
private var mapView: GMSMapView!
is used for mapView but couldn't find any GMSMapView! in storyboard connection .
From Storyboard i found
#IBOutlet var mapView: MKMapView!
that makes the problem . when i used exampled google map it throws error
this class is not key value coding-compliant for the key mapView.'
Here the complete code :
import UIKit
import MapKit
import GooglePlaces
import GoogleMaps
// Point of Interest Item which implements the GMUClusterItem protocol.
class POIItem: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
var name: String!
init(position: CLLocationCoordinate2D, name: String) {
self.position = position
self.name = name
}
}
let kClusterItemCount = 10000
let kCameraLatitude = -33.8
let kCameraLongitude = 151.2
class FirstViewController: UIViewController , GMUClusterManagerDelegate,
GMSMapViewDelegate {
// #IBOutlet var mapView: MKMapView!
private var mapView: GMSMapView!
private var clusterManager: GMUClusterManager!
override func viewDidLoad() {
super.viewDidLoad()
// Set up the cluster manager with the supplied icon generator and
// renderer.
// Set up the cluster manager with default icon generator and renderer.
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
// Generate and add random items to the cluster manager.
generateClusterItems()
// Call cluster() after items have been added to perform the clustering and rendering on map.
clusterManager.cluster()
// Register self to listen to both GMUClusterManagerDelegate and GMSMapViewDelegate events.
clusterManager.setDelegate(self, mapDelegate: self)
}
// override func loadView() {
//
// // Create a GMSCameraPosition that tells the map to display the
// // coordinate -33.86,151.20 at zoom level 6.
// let camera = GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 6.0)
// let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
// view = mapView
//
// // Creates a marker in the center of the map.
// let marker = GMSMarker()
// marker.position = CLLocationCoordinate2D(latitude: -33.86, longitude: 151.20)
// marker.title = "Sydney"
// marker.snippet = "Australia"
// marker.map = mapView
//
// }
//
// MARK: - GMUClusterManagerDelegate
func clusterManager(clusterManager: GMUClusterManager, didTapCluster cluster: GMUCluster) {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position,
zoom: mapView.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
mapView.moveCamera(update)
}
// MARK: - GMUMapViewDelegate
func mapView(mapView: GMSMapView, didTapMarker marker: GMSMarker) -> Bool {
if let poiItem = marker.userData as? POIItem {
NSLog("Did tap marker for cluster item \(poiItem.name)")
} else {
NSLog("Did tap a normal marker")
}
return false
}
// MARK: - Private
/// Randomly generates cluster items within some extent of the camera and adds them to the
/// cluster manager.
private func generateClusterItems() {
let extent = 0.2
for index in 1...kClusterItemCount {
let lat = kCameraLatitude + extent * randomScale()
let lng = kCameraLongitude + extent * randomScale()
let name = "Item \(index)"
let item = POIItem(position: CLLocationCoordinate2DMake(lat, lng), name: name)
clusterManager.add(item)
}
}
/// Returns a random value between -1.0 and 1.0.
private func randomScale() -> Double {
return Double(arc4random()) / Double(UINT32_MAX) * 2.0 - 1.0
}
}
First Take UIView:
Add UIView In UIViewController:
Assign class GMSMap View
And Now create outlet of GMSMapView.
#IBOutlet var mapView: GMSMapView!
To add GMSMapView in Storyboard in IOS, open the Identity Inspector and under Custom Class add GMSMapView. You may follow this tutorial about Google Maps SDK for iOS in Xcode Storyboard for the step-by-step instructions. For your error this class is not key value coding-compliant for the key mapView, you might have created an outlet called mapview and deleted it later. Check whether the outlets of MapView is broken in Xib/Storyboard. Here are also some references which might help: https://www.raywenderlich.com/109888/google-maps-ios-sdk-tutorial and What does this mean? "'NSUnknownKeyException', reason: … this class is not key value coding-compliant for the key X"
I am facing a weird issue while using GoogleMapsSDK. On my view that is showing the Google Map, a navigation controller is embedded. On the nav bar, I have a bar button that I have connected to a new view. When the button is pressed, the segue is laggy and doesn't show any content.
Here is what is happening: http://gph.is/2putLtQ
Not sure what the issue is. I have the same set up working without GoogleMapsSDK implemented.
Here is the GoogleMaps view controller:
import UIKit
import GoogleMaps
class GoogleMapsViewController: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate {
var locationManager = CLLocationManager()
var tacoLocations = [TacoLocation]()
var tacoLocationPlace_id :String!
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager = CLLocationManager()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLDistanceFilterNone
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
let lat = self.locationManager.location?.coordinate.latitude
let lng = self.locationManager.location?.coordinate.longitude
// creates the map and zooms the current user location, at a 15.0 zoom
let camera = GMSCameraPosition.camera(withLatitude: lat!, longitude: lng!, zoom: 15.0)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
view = mapView
for location in self.tacoLocations {
let marker = GMSMarker()
let lat = location.locationLat
let lng = location.locationLng
marker.position = CLLocationCoordinate2D(latitude: lat!, longitude: lng!)
marker.title = location.name
if location.open_now == false {
marker.snippet = "\(location.vicinity!)\nClosed"
} else if location.open_now == true {
marker.snippet = "\(location.vicinity!)\nOpen"
} else {
}
marker.userData = location
marker.icon = UIImage(named: "taco_marker.png")
marker.infoWindowAnchor = CGPoint(x: 0.5, y: 0.2)
marker.map = mapView
}
// enable my location dot
mapView.isMyLocationEnabled = true
mapView.delegate = self
}
//MARK: GMSMapViewDelegate
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
let customWindow = Bundle.main.loadNibNamed("CustomInfoWindow", owner: self, options: nil)?.first as! CustomInfoWindow
customWindow.nameLabel.text = marker.title
customWindow.addressLabel.text = marker.snippet
return customWindow
}
func mapView(_ mapView: GMSMapView, didTapInfoWindowOf marker: GMSMarker) {
let tacoLocation = marker.userData as! TacoLocation
self.tacoLocationPlace_id = tacoLocation.place_id
DispatchQueue.main.async {
self.performSegue(withIdentifier: "MoreInfoSegue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MoreInfoSegue" {
let tabVC = segue.destination as! UITabBarController
let moreInfoVC = tabVC.viewControllers?[0] as! MoreInfoViewController
let reviewVC = tabVC.viewControllers?[1] as! ReviewViewController
moreInfoVC.tacoLocationPlace_id = self.tacoLocationPlace_id
reviewVC.tacoLocationPlace_id = self.tacoLocationPlace_id
} else if segue.identifier == "ARSegue" {
//segue to new view that is not working correctly.
}
}
}
The only thing in the second view controller is the viewdidload.
Any help is much appreciated!
I uninstalled the google maps pods and then reinstalled them. That fixed my issue. Must have been a bug with xcode.
I'm quite new to Swift and i'm trying to better understand Google Maps API. I'm building a simple app that shows images when markers on panoramaView are tapped through didTapMarker method. Since each marker should show a different images, i'm trying to find a way to identify which marker has been tapped, a sort of marker tag.
All suggestions are welcome.
Down here is a prototype of the code with 2 markers and 2 images. Not really sure how to do it, but didTapMarker method should show randomImage when marker is tapped and randomImage2 when marker2 is tapped. So far it only shows randomImage when both marker and marker1 are tapped.
import UIKit
import GoogleMaps
class ViewController: UIViewController, GMSPanoramaViewDelegate {
#IBOutlet weak var viewStreet: UIView!
#IBOutlet weak var randomImage: UIImageView!
#IBOutlet weak var randomImage2: UIImageView!
var panoView: GMSPanoramaView!
override func viewDidLoad() {
super.viewDidLoad()
randomImage.hidden = true
randomImage2.hidden = true
let panoView = GMSPanoramaView(frame: CGRectMake(200, 200, 400, 400))
panoView.delegate = self
panoView.moveNearCoordinate(CLLocationCoordinate2D(latitude: -33.732, longitude: 150.312))
viewStreet.addSubview(panoView)
viewStreet.sendSubviewToBack(panoView)
let position = CLLocationCoordinate2D(latitude: -33.732, longitude: 150.312)
let marker = GMSMarker(position: position)
marker.panoramaView = panoView
let position2 = CLLocationCoordinate2D(latitude: -33.732, longitude: 150.311)
let marker2 = GMSMarker(position: position2)
marker2.panoramaView = panoView
}
func panoramaView(panoramaView: GMSPanoramaView, didTapMarker marker: GMSMarker) -> Bool {
randomImage.hidden = false
randomImage2.hidden = true
return true
}
}
EDIT: solved, thanks to everyone, i'm adding a trivial example on how to do it then.
marker.userData = "example"
Then didTapMarker method is always called when a marker is tapped, but randomImage 's propriety is set to false only when the marker tapped is the one above.
func panoramaView(panoramaView: GMSPanoramaView, didTapMarker marker: GMSMarker) -> Bool {
if marker.userData as? String == "example" {
randomImage.hidden = false
}
return true
}
Code can be improved making use of a dictionary to handle multiple markers but it's up to you. :)
put the data of that marker in userData of that marker. Make use of that that whenever marker is tapped in didTapInfoWindowOfMarker api.
I'm playing with google maps and I need to override default behavior of tapping on the marker - by default marker goes to center of the screen and infowindow is being shown above. I need to figure out a way that when marker is tapped marker moves to the bottom of screen and infowindow shows on center. I found solutions here but I couldnt translate it to to swift
Any help please?
func mapView(mapView: GMSMapView!, didTapMarker marker: GMSMarker!) -> Bool {
mapView.animateToLocation(marker.position)
mapView.selectedMarker = marker
var point = mapView.projection.pointForCoordinate(marker.position)
point.y = point.y - 200
var newPoint = mapView.projection.coordinateForPoint(point)
var camera = GMSCameraUpdate.setTarget(newPoint)
mapView.animateWithCameraUpdate(camera)
return true
}
add GMSMapViewDelegate
// move marker
func updateLocationoordinates(coordinates:CLLocationCoordinate2D) {
if marker == nil
{
marker = GMSMarker()
marker.position = coordinates
let image = UIImage(named:"destinationmarker")
marker.icon = image
marker.map = mapPageView
marker.appearAnimation = GMSMarkerAnimation.pop
}
else
{
CATransaction.begin()
// CATransaction.setAnimationDuration(0.1)
marker.position = coordinates
CATransaction.commit()
}
print(coordinates)
}
Camera change Position this methods will call every time
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
var destinationLocation = CLLocation()
destinationLocation = CLLocation(latitude: position.target.latitude, longitude: position.target.longitude)
destinationCoordinate = destinationLocation.coordinate
updateLocationoordinates(coordinates: destinationCoordinate)
}
good luck