How to cluster custom icons markers in GoogleMaps for iOS - ios

I'm developing an app on which I want to show a lot of event on the map. The user can click on an event and see a lot of information about it.
I customized the marker icon of each event with a custom image and now I want to cluster each custom markers.
I'm able to cluster the default icon of GoogleMaps API but if I want to cluster my own marker icon I'm not able to do it.
Here's my current code :
var mapView: GMSMapView!
var clusterManager: GMUClusterManager!
let isClustering: Bool = true
let isCustom: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
mapView = GMSMapView(frame: view.frame)
mapView.camera = GMSCameraPosition.camera(withLatitude: 13.756331, longitude: 100.501765, zoom: 12.0)
mapView.mapType = .normal
mapView.delegate = self
view.addSubview(mapView)
if isClustering {
var iconGenerator: GMUDefaultClusterIconGenerator!
if isCustom { // Here's my image if the event are clustered
var images: [UIImage] = [UIImage(named: "m1.png")!, UIImage(named: "m2.png")!, UIImage(named: "m3.png")!, UIImage(named: "m4.png")!, UIImage(named: "m5.png")!]
iconGenerator = GMUDefaultClusterIconGenerator(buckets: [5, 10, 15, 20, 25], backgroundImages: images)
} else {
iconGenerator = GMUDefaultClusterIconGenerator()
}
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
clusterManager.cluster()
clusterManager.setDelegate(self, mapDelegate: self)
} else {
}
// Here's my personal marker icon (for one location)
let firstLocation = CLLocationCoordinate2DMake(48.898902, 2.282664)
let marker = GMSMarker(position: firstLocation)
marker.icon = UIImage(named: "pointeurx1") //Apply custom marker
marker.map = mapView
let secondLocation = CLLocationCoordinate2DMake(48.924572, 2.360207)
let secondMarker = GMSMarker(position: secondLocation)
secondMarker.icon = UIImage(named: "pointeurx1")
secondMarker.map = mapView
let threeLocation = CLLocationCoordinate2DMake(48.841619, 2.253113)
let threeMarker = GMSMarker(position: threeLocation)
threeMarker.icon = UIImage(named: "pointeurx1")
threeMarker.map = mapView
let fourLocation = CLLocationCoordinate2DMake(48.858575, 2.294556)
let fourMarker = GMSMarker(position: fourLocation)
fourMarker.icon = UIImage(named: "pointeurx1")
fourMarker.map = mapView
let fiveLocation = CLLocationCoordinate2DMake(48.873819, 2.295200)
let fiveMarker = GMSMarker(position: fiveLocation)
fiveMarker.icon = UIImage(named: "pointeurx1")
fiveMarker.map = mapView
}
/// 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
}
}
func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position, zoom: mapView.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
mapView.moveCamera(update)
}
}
How can I do it?
Look at these screenshots of my app then maybe you could understand better my issue.
First one there are the red default markers icons of the Google Maps, you can see in blue the cluster icon I was added in my project. Then you understand I added some locations on the viewDidLoad(), then the red markers are that. You can also see two others differents markers, the google one is orange and another one is my personal marker icon that I want to use for each marker icon of a location. But you can also see the issue, the issue is the blue cluster icon don't add the markers icons I added on the map (it shows 4 inside the blue cluster icon, it's the 4 icons around it but when the blue cluster icon appears the markers icons around it don't disappear.
Second image, if I make a zoom, the blue cluster icon disappears but you can also see another issue, the locations I was added have another red default markers icons of the Google Maps appears above them (you can see it at less because of my personal orange marker icon

You are actually clustering first then adding markers thats why this is happening.
What you should actually do is
class MarkerModel: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
var name: String
init(position: CLLocationCoordinate2D, name: String) {
self.position = position
self.name = name
}
}
override func viewDidLoad() {
super.viewDidLoad()
mapView = GMSMapView(frame: view.frame)
mapView.camera = GMSCameraPosition.camera(withLatitude: 13.756331, longitude: 100.501765, zoom: 12.0)
mapView.mapType = .normal
mapView.delegate = self
view.addSubview(mapView)
if isClustering {
var iconGenerator: GMUDefaultClusterIconGenerator!
if isCustom { // Here's my image if the event are clustered
var images: [UIImage] = [UIImage(named: "m1.png")!, UIImage(named: "m2.png")!, UIImage(named: "m3.png")!, UIImage(named: "m4.png")!, UIImage(named: "m5.png")!]
iconGenerator = GMUDefaultClusterIconGenerator(buckets: [5, 10, 15, 20, 25], backgroundImages: images)
} else {
iconGenerator = GMUDefaultClusterIconGenerator()
}
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
} else {
}
}
func addMarkers(cameraLatitude : Float, cameraLongitude : Float) {
let extent = 0.01
for index in 1...clusterItemCount {
let lat = cameraLatitude + extent * randomScale()
let lng = cameraLongitude + extent * randomScale()
let name = "Item \(index)"
let position = CLLocationCoordinate2DMake(lat, lng)
let item = MarkerModel(position: position, name: name)
item.icon = #imageLiteral(resourceName: "marker")
clusterManager.add(item)
}
clusterManager.cluster()
clusterManager.setDelegate(self, mapDelegate: self)
}
func randomScale() -> Double {
return Double(arc4random()) / Double(UINT32_MAX) * 2.0 - 1.0
}
func renderer(_ renderer: GMUClusterRenderer, markerFor object: Any) -> GMSMarker? {
let marker = GMSMarker()
if let model = object as? MarkerModel {
// set image view for gmsmarker
}
return marker
}
func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
let newCamera = GMSCameraPosition.camera(withTarget: cluster.position, zoom: mapView.camera.zoom + 1)
let update = GMSCameraUpdate.setCamera(newCamera)
mapView.moveCamera(update)
return false
}

Related

Google Map Cluster not working in first time load in iOS

I have implemented Google Map Clustering for Google Map markers. I am facing issue when i load/add marker for clustering for the first time it is showing Icons and Count both but when i zoom in all the way and zoom out it is working as expected(without markers only count).
Please check below code and Screenshot.
When loading Clustering for the first time
After Zoom in all the way and zoom out (Expected behaviour)
Pods for clustering
pod 'GoogleMaps'
pod 'GooglePlaces'
pod 'Google-Maps-iOS-Utils'
Code for clustering below:
//MARK:- SETUP CLUSTERING
private func setupClustering(){
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: googleMap,
clusterIconGenerator: iconGenerator)
clusterManager = GMUClusterManager(map: googleMap, algorithm: algorithm,
renderer: renderer)
self.clusterManager.cluster()
clusterManager.setMapDelegate(self)
clusterManager.setDelegate(self, mapDelegate: self)
}
CLUSTERING METHOD
private func addClusteredMarker(){
googleMap.clear()
clusterManager.clearItems()
clusterManager.cluster()
let haveD = UIImage(named: "HaveD")
let needD = UIImage(named: "NeedD")
var arrMarkers = [GMSMarker]()
for post in arrRecentPost {
let marker = GMSMarker()
let coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(post.latitude)!, longitude: CLLocationDegrees(post.longitude)!)
marker.position = coordinate
marker.title = post.siteName
marker.snippet = post.materialType.name
marker.accessibilityHint = post.slug
// marker.zIndex = index
let custM:CustMarker = CustMarker.instancefromNib() as! CustMarker
custM.frame = CGRect(x: 0, y: 0, width: 55, height: 50)
if post.type == "Have" {custM.imgMarker.image = haveD}
else if post.type == "Need" {custM.imgMarker.image = needD}
custM.lblCount.backgroundColor = post.type == "Need" ? UIColor(named: "AppSecond")! : UIColor(named: "App")!
custM.backgroundColor = .clear
custM.lblCount.text = post.placeCount == 0 ? "" : "+\(post.placeCount)"
custM.lblCount.isHidden = post.placeCount == 0 ? true : false
custM.lblCount.setRounded()
marker.userData = post
marker.map = googleMap
marker.iconView = custM
arrMarkers.append(marker)
}
clusterManager.add(arrMarkers)
clusterManager.cluster()
}

MKMapView - Show Customizable Gridlines

I want these lines to be visible on a regular map in such a way where each square represents 1x1m.
I looked into MKTileOverlay but didn't find too much about it. Is it possible to show the gridline on the map as well as change the color?
I've done something very similar for an app I've been playing around with. Mine is for putting a coloured grid over a map so that there are 15 columns and rows in a square mile around a home location, so you'll need to adjust the calculations for your distances but the same general approach should work. The app is only a prototype at the moment, and hasnt been optimised (could refactor code out of viewDidLoad for a start!), but the code should be good enough to get you started.
var homeLocation: CLLocationCoordinate2D!
let metresPerMile = 1609.344
var degPerHorizEdge: Double!
var degPerVertEdge: Double!
override func viewDidLoad() {
homeLocation = CLLocationCoordinate2D(latitude: 53.7011, longitude: -2.1071)
let hd = CLLocation(latitude: homeLocation.latitude, longitude: homeLocation.longitude).distance(from: CLLocation(latitude: homeLocation.latitude + 1, longitude: homeLocation.longitude))
let vd = CLLocation(latitude: homeLocation.latitude, longitude: homeLocation.longitude).distance(from: CLLocation(latitude: homeLocation.latitude, longitude: homeLocation.longitude + 1))
let degPerHMile = 1 / (hd / metresPerMile)
let degPerVMile = 1 / (vd / metresPerMile)
degPerHorizEdge = degPerHMile / 15
degPerVertEdge = degPerVMile / 15
super.viewDidLoad()
let gridController = GridController(for: gameID!)
gridController.delegate = self
let mapSize = CLLocationDistance(1.2 * metresPerMile)
let region = MKCoordinateRegion(center: homeLocation, latitudinalMeters: mapSize, longitudinalMeters: mapSize)
mapView.delegate = self
mapView.showsUserLocation = true
mapView.showsBuildings = true
mapView.mapType = .standard
mapView.setRegion(region, animated: true)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let overlays = prepareOverlays() {
mapView.addOverlays(overlays)
}
}
func prepareOverlays() -> [MKPolygon]? {
let topLeft = CLLocationCoordinate2D(latitude: homeLocation.latitude - 7.5 * degPerHorizEdge, longitude: homeLocation.longitude - degPerVertEdge * 7.5)
var overlays = [MKPolygon]()
var locations = [CLLocationCoordinate2D]()
for y in 0...14 {
for x in 0...14 {
locations.append(CLLocationCoordinate2D(latitude: topLeft.latitude + Double(x) * degPerHorizEdge, longitude: topLeft.longitude + Double(y) * degPerVertEdge))
}
}
for coord in locations.enumerated() {
let location = coord.element
var corners = [location, //has to be a var due to using pointer in next line
CLLocationCoordinate2D(latitude: location.latitude + degPerHorizEdge, longitude: location.longitude),
CLLocationCoordinate2D(latitude: location.latitude + degPerHorizEdge, longitude: location.longitude + degPerVertEdge),
CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude + degPerVertEdge)]
let overlay = MKPolygon(coordinates: &corners, count: 4)
overlay.title = "\(coord.offset)"
overlays.append(overlay)
}
return overlays.count > 0 ? overlays : ni
}
//MARK:- MKMapViewDelegate
extension MapViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
// overlay is a WSW zone
if let polygon = overlay as? MKPolygon {
let renderer = MKPolygonRenderer(polygon: polygon)
renderer.strokeColor = UIColor.gray.withAlphaComponent(0.4)
renderer.fillColor = UIColor.orange.withAlphaComponent(0.5)
renderer.lineWidth = 2
return renderer
}
// overlay is a line segment from the run (only remaining overlay type)
else {
let renderer = MKPolylineRenderer(polyline: overlay as! MKPolyline)
renderer.strokeColor = UIColor.blue.withAlphaComponent(0.8)
renderer.lineWidth = 3
return renderer
}
}
}

Add two coordinates in a button function to launch mapKit and start navigation between two points (Swift)

I'm using this class
import UIKit
import CoreLocation
import GoogleMaps
import GooglePlaces
import SwiftyJSON
import Alamofire
import MapKit
class FinalClass: UIViewController {
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var bottomInfoView: UIView!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var distanceLabel: UILabel!
var userLocation:CLLocationCoordinate2D?
var places:[QPlace] = []
var index:Int = -1
var locationStart = CLLocation()
var locationEnd = CLLocation()
var mapView:GMSMapView!
var marker:GMSMarker?
override func loadView() {
super.loadView()
}
override func viewDidLoad() {
super.viewDidLoad()
guard index >= 0, places.count > 0 else {
return
}
let place = places[index]
let lat = place.location?.latitude ?? 1.310844
let lng = place.location?.longitude ?? 103.866048
// Google map view
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: lng, zoom: 12.5)
mapView = GMSMapView.map(withFrame: self.view.bounds, camera: camera)
mapView.autoresizingMask = [.flexibleHeight, .flexibleWidth, .flexibleTopMargin, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin]
self.containerView.addSubview(mapView)
// Add gesture
addSwipeGesture()
didSelect(place: place)
if userLocation != nil {
addMarkerAtCurrentLocation(userLocation!)
}
}
func addSwipeGesture() {
let directions: [UISwipeGestureRecognizerDirection] = [.right, .left]
for direction in directions {
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(sender:)))
gesture.direction = direction
self.bottomInfoView.addGestureRecognizer(gesture)
}
}
func addMarkerAtCurrentLocation(_ userLocation: CLLocationCoordinate2D) {
let marker = GMSMarker()
marker.position = userLocation
marker.title = "Your location"
marker.map = mapView
}
func didSelect(place:QPlace) {
guard let coordinates = place.location else {
return
}
// clear current marker
marker?.map = nil
// add marker
marker = GMSMarker()
marker?.position = coordinates
marker?.title = place.name
marker?.map = mapView
mapView.selectedMarker = marker
moveToMarker(marker!)
// update bottom info panel view
let desc = place.getDescription()
descriptionLabel.text = desc.characters.count > 0 ? desc : "-"
distanceLabel.text = "-"
// update distance
if userLocation != nil {
let dist = distance(from: userLocation!, to: coordinates)
distanceLabel.text = String.init(format: "Distance %.2f meters", dist)
self.drawPath(startLocation: userLocation!, endLocation: coordinates)
}
title = place.name
}
func moveToMarker(_ marker: GMSMarker) {
let camera = GMSCameraPosition.camera(withLatitude: marker.position.latitude,
longitude: marker.position.longitude,
zoom: 12.5)
self.mapView.animate(to: camera)
}
// distance between two coordinates
func distance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> CLLocationDistance {
let from = CLLocation(latitude: from.latitude, longitude: from.longitude)
let to = CLLocation(latitude: to.latitude, longitude: to.longitude)
return from.distance(from: to)
}
func handleSwipe(sender: UISwipeGestureRecognizer) {
guard index >= 0, places.count > 0 else {
return
}
if sender.direction == .left {
if index < places.count - 2 {
index += 1
didSelect(place: places[index])
}
} else if sender.direction == .right {
if index > 1 {
index -= 1
didSelect(place: places[index])
}
}
}
func drawPath(startLocation: CLLocationCoordinate2D, endLocation: CLLocationCoordinate2D) {
let from = CLLocation(latitude: startLocation.latitude, longitude: startLocation.longitude)
let to = CLLocation(latitude: endLocation.latitude, longitude: endLocation.longitude)
let origin = "\(from.coordinate.latitude),\(from.coordinate.longitude)"
let destination = "\(to.coordinate.latitude),\(to.coordinate.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving"
Alamofire.request(url).responseJSON { response in
print(response.request as Any) // original URL request
print(response.response as Any) // HTTP URL response
print(response.data as Any) // server data
print(response.result as Any) // result of response serialization
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
// print route using Polyline
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.black
polyline.map = self.mapView
}
}
}
#IBAction func navigationStart(_ sender: Any) {
}
with a google maps to add place markers, draw the direction on the map and show the distance between two points, now i would like to launch the navigator between startLocation: userLocation! and endLocation: coordinates but with some research i saw that i can not launch the navigator in the same view, i need to open the maps application, so i decided to add the MapKit and a button
#IBAction func navigationStart(_ sender: Any) {
}
so how can i do that by pressing the button the map application opens with direction from userLocation to coordinates ? I already looked to similar question but is a little different to my problem, because i already have the points but in different format.
Your question is a little confusing but if you want to open the maps app and show direction from a user's current location to another point on the map then you don't need to pass the user's location, just the destination:
Swift 4:
let coordinate = CLLocationCoordinate2DMake(51.5007, -0.1246)
let placeMark = MKPlacemark(coordinate: coordinate)
let mapItem = MKMapItem(placemark: placeMark)
mapItem.name = "Big Ben"
mapItem.openInMaps(launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving])
Objective C:
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(51.5007, -0.1246);
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate: coordinate];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:#"Big Ben"];
[mapItem openInMapsWithLaunchOptions:#{MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving}];

Update GMSMarker location as realtime message received Swift 3.1

I am new to swift. I am working on an app which shows markers moving on location update when realtime message is received.
View and Steps
Home (Map Screen which will show tracking results) and Search Button
On search button click, a new search view has been displayed. User
types and search
On search result view if found, a table view is shown. User can
select multiple to subscribe and "Add to tracking list"
On "Add to tracking list", app subscribe on realtime api and should start displaying results (on first view - Home) as message received.
Issue:
I am using delegate to share data (method: messageReceived) from MesssagingProcessor class to FirstViewController. Problem is "messageReceived" is not called in MesssagingProcessor class because delegate is nil.
To go back to first, I used following code
self.navigationController?.popToRootViewController(animated: true)
To subscribe,
channel.subscribe { message in
print(message.name ?? Constant.NIL_DEFAULT_TEXT)
print(message.data ?? Constant.NIL_DEFAULT_TEXT)
self.messageProcessor.process(message: message)
}
return true
I am using delegate to share data between classes and viewcontrollers
Delegate Class:
protocol MesssagingProcessorDelegate {
func messageReceived(msg: MessageMO)
}
class MesssagingProcessor {
//MAR: Properties
var delegate: MesssagingProcessorDelegate?
var info = ""
//MARK: Constructor
init() {
info = "I am set"
}
//MARK: Functions
func process(message: <MessageTypeHere>) {
let msg = MessageMO(dataString: message.data as! String, colString: Constant.EP.C_MSG)
if MessagingHelper.validMessage(msg: msg) {
if msg.type == Constant.TYPE_MSG_LOC {
if msg.location != nil {
delegate?.messageReceived(msg: msg)
}
else {
print("No location found in Location Message. Message: \(String(describing: message.data))")
}
}
}
}
}
Home View Controller:
import UIKit
import GoogleMaps
import UserNotifications
class FirstViewController: UIViewController, MesssagingProcessorDelegate {
//MARK: Properties
let messsagingProcessor: MesssagingProcessor = MesssagingProcessor()
var bounds = GMSCoordinateBounds()
var mapView: GMSMapView? = nil
//MARK: Events
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton.init(type: .custom)
button.setImage(UIImage.init(named: "logo"), for: UIControlState.normal)
button.addTarget(self, action:#selector(showTrackeeOptions), for: UIControlEvents.touchUpInside)
button.frame = CGRect.init(x: 0, y: 0, width: 30, height: 30) //CGRectMake(0, 0, 30, 30)
let barButton = UIBarButtonItem.init(customView: button)
self.navigationItem.leftBarButtonItem = barButton
let camera = GMSCameraPosition.camera(withLatitude: 53.34624,
longitude: -6.24134, zoom: 6)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView!.isMyLocationEnabled = true
mapView!.settings.setAllGesturesEnabled(true)
mapView!.delegate = self
self.view = mapView!
//
let marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake(-33.86, 151.20)
marker.title = "TEST"
marker.snippet = Generic.toImageURL(name: "_demo_bus.png", category: Constant.TYPE_IMG_MARKER, type: Constant.TYPE_USER) + "^TestTest Test <-> Demo Bus^Available^2.3 km/h^1493729075106^10^0^333"
marker.map = mapView!
messsagingProcessor.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: Events
//MARK: MesssagingProcessorDelegate
func messageReceived(msg: MessageMO) {
let mk = MarkerMO(msg: msg).add()
var marker: GMSMarker
if mk != nil {
let imgURL = Generic.toImageURL(name: mk!.iconMarker, category: Constant.TYPE_IMG_MARKER, type: Constant.TYPE_USER)
var sharedInfo = imgURL
sharedInfo += Constant.SEPARATOR_LIST_ITEM
sharedInfo += mk!.name! + Constant.SEPARATOR_LIST_ITEM
sharedInfo += mk!.status + Constant.SEPARATOR_LIST_ITEM
sharedInfo += mk!.speed + Constant.SEPARATOR_LIST_ITEM
sharedInfo += String(mk!.time) + Constant.SEPARATOR_LIST_ITEM
sharedInfo += String(mk!.interval)
if mk!.gMarker != nil {
marker = GMSMarker()
} else {
marker = mk!.gMarker!
}
CATransaction.begin()
CATransaction.setAnimationDuration(1.0)
marker.position = CLLocationCoordinate2D(latitude: (mk!.location!.latitude), longitude: (mk!.location!.longitude))
marker.icon = Generic.toImageByURL(url: imgURL, width: Constant.ICON_DEFAULT_MARKER_WIDTH, height: Constant.ICON_DEFAULT_MARKER_HEIGHT, defaultImage: "defaultmarker")
marker.title = mk!.name
marker.snippet = sharedInfo
marker.map = self.mapView
CATransaction.commit()
mk!.updateGMarker(marker: marker)
self.bounds = self.bounds.includingCoordinate(marker.position)
}
else {
//TODO: Error in marker generation
}
}
}
extension FirstViewController: GMSMapViewDelegate {
//For Info WindowIndow
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
let infoWindow = Bundle.main.loadNibNamed("LocMarkerInfoWindow", owner: self.view, options: nil)!.first! as! LocMarkerInfoWindowController
print(marker.snippet!)
let info = marker.snippet!.components(separatedBy: Constant.SEPARATOR_LIST_ITEM)
infoWindow.iconMarker.image = Generic.toImageByURL(url: info[0], width: Constant.ICON_INFOWIN_MARKER_WIDTH, height: -1, defaultImage: "defaultmarker")
infoWindow.name.text = info[1]
infoWindow.status.text = info[2]
infoWindow.speed.text = info[3]
infoWindow.lastUpdatedOn.text = Double(info[4])?.getDateStringFromTimeStamp()
infoWindow.interval.text = info[5]
return infoWindow
}
}
I will really appreciate any help regarding this. Thank you
I have resolved the issue by declaring messsagingProcessor as global and using it in view controller and class.
let messsagingProcessor: MesssagingProcessor = MesssagingProcessor()
Previously, I was declaring and using different objects in view controller class and client class.
I hope it may help someone. Thanks anyway

Custom info window for selected place not showing up (Google Maps/Places API)

I'm using the Google Places API, and have implemented their pickPlace function which looks like this:
func pickPlace() {
let center = CLLocationCoordinate2D(latitude: 40.708637, longitude: -74.014839)
let northEast = CLLocationCoordinate2D(latitude: center.latitude + 0.001, longitude: center.longitude + 0.001)
let southWest = CLLocationCoordinate2D(latitude: center.latitude - 0.001, longitude: center.longitude - 0.001)
let viewport = GMSCoordinateBounds(coordinate: northEast, coordinate: southWest)
let config = GMSPlacePickerConfig(viewport: viewport)
let placePicker = GMSPlacePicker(config: config)
placePicker.pickPlace(callback: {(place, error) -> Void in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
return
}
if let place = place {
// Set place to class variable selectedPlace
self.selectedPlace = place
// Add marker & move camera to new place
if self.selectedPlace != nil {
let cam = GMSCameraPosition.camera(withTarget: (self.selectedPlace?.coordinate)!, zoom: 18)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: cam)
let newPlaceMarker = GMSMarker(position: (self.selectedPlace?.coordinate)!)
newPlaceMarker.map = mapView
self.navigationItem.title = self.selectedPlace?.name
print(self.selectedPlace?.website)
newPlaceMarker.title = self.selectedPlace?.name
self.view = mapView
}
} else {
self.navigationItem.title = "No place selected"
}
})
}
So this allows the user to search for a place like "Starbucks" and sets place to the variable var selectedPlace: GMSPlace? (declared at class scope): the map moves there, adds a marker at that location, changes the navigationItem.title to the selectedPlace.name, and prints the website to the console - all good so far.
Now I'd like an info window to pop up when the marker is tapped, like I've done with some other default markers that I've hardcoded. Here's the infoWindow function:
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
let customInfoWindow = Bundle.main.loadNibNamed("CustomInfoWindow", owner: self, options: nil)?[0] as! CustomInfoWindow
let placeName = marker.title!
switch placeName {
case "TGI Friday's":
customInfoWindow.nameLbl.text = "TGI Friday's"
customInfoWindow.detailLabel.text = "Thoroughly Average Chain Restaurant"
customInfoWindow.placeImage.image = UIImage(named: "fridays")
self.navigationItem.title = "TGI Friday's"
case "George's":
customInfoWindow.nameLbl.text = "George's"
customInfoWindow.detailLabel.text = "Old School Diner"
customInfoWindow.placeImage.image = UIImage(named: "georges")
self.navigationItem.title = "George's"
case "Reserve Cut":
customInfoWindow.nameLbl.text = "Reserve Cut"
customInfoWindow.detailLabel.text = "Kosher Steakhouse"
customInfoWindow.placeImage.image = UIImage(named: "reserveCut")
self.navigationItem.title = "Reserve Cut"
case "O'Hara's":
customInfoWindow.nameLbl.text = "O'Hara's"
customInfoWindow.detailLabel.text = "Irish Pub"
customInfoWindow.placeImage.image = UIImage(named: "oharas")
self.navigationItem.title = "O'Hara's"
case "Bill's Bar & Burger":
customInfoWindow.nameLbl.text = "Bill's Bar & Burger"
customInfoWindow.detailLabel.text = "Bar founded by Bill that also has burgers"
customInfoWindow.placeImage.image = UIImage(named: "bills")
self.navigationItem.title = "Bill's Bar & Burger"
default:
customInfoWindow.nameLbl.text = self.selectedPlace?.name
customInfoWindow.detailLabel.text = self.selectedPlace?.formattedAddress
customInfoWindow.placeImage.image = UIImage(named: "noImageFound")
self.navigationItem.title = self.selectedPlace?.name
}
return customInfoWindow
}
My custom window pops up fine when I tap on my hardcoded default markers, but not with the user-selected place. The title pops up in the default info window but not my custom window. Does anybody know what's going on and how I can get this to work?
EDIT: If I print(selectedPlace?.website) in a different function, it's nil. Not sure why it works fine within the pickPlace function but not outside - that's why I set self.selectedPlace = place, so I could use it around my class.
Anyway that's what's causing the issue at hand I think, but I don't know why or how to fix it. So if anyone can help me fix it you're awesome.

Resources