Transferring Data from Firebase into Custom Info Window - swift

So I'm trying to transfer the data I've snapshotted from firebase into the custom info window. I currently have four different categories of activities and as such there are four different marker arrays and functions. I have one generic custom info window that I wish to display the markers Title, rating and difficulty level into.
I am having an issue Ive currently tried appending all data into one structured array and then calling the data from that array but all I get is the same set of data in all the info windows. I want each info window to specifically display the data associated with that GMS Marker.
This is is the function that shows the board activities. I have four of these functions for each activity.
func showBoardIcon() {
ref = Database.database().reference()
ref.child("location").observe(.childAdded) { (snapshot:DataSnapshot) in
if let dict = snapshot.value as? [String:AnyObject] {
if dict["Activity"] as! String == "Board" {
let longitude = dict["Longitude"] as! String
let lattitude = dict["Lattitude"] as! String
let title = dict["Title"] as! String
let key = dict["id"] as! String
self.boardIconArray.insert(coordinate(title: title, carLat: lattitude, carLng: longitude, idKey: key), at: 0)
let n = self.boardIconArray.count
let heightWidth = (self.mapView.frame.height / 12)
for var Marker in 1...n {
let boardMarker = GMSMarker()
let boardIconView = UIImage(named: "boardPin")
let image = boardIconView
let location = CLLocationCoordinate2D(latitude: Double(lattitude)!, longitude: Double(longitude)!)
boardMarker.position = location
boardMarker.icon = image
boardMarker.title = title
boardMarker.icon = self.image(image!, scaledToSize: CGSize(width: heightWidth, height: heightWidth))
func displayBoard() {
if self.boardNumber == "1" {
boardMarker.map = self.mapView
self.arrBoardMarker.append(boardMarker)
} else {
boardMarker.map = nil
}
}
displayBoard()
break
}
}
}
}
}
This is the function that displays the custom info window.
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
let Markerview: infoWindow = UIView.fromNib()
let a = arrCarMarkers.count
let b = arrLegMarker.count
let c = arrWaterMarker.count
let d = arrBoardMarker.count
let all = 0 + a + b + d + c
Markerview.titleLbl.text = arrAllMarkers[key].title
Markerview.ratingLbl.text = ("\(arrAllMarkers[all].rating)/5")
Markerview.difficultyLbl.text = arrAllMarkers[all].diff
Markerview.idKey.text = arrAllMarkers[all].key
transferKey = arrAllMarkers[all].key
Markerview.alpha = 0.8
Markerview.layer.cornerRadius = 30
return Markerview
}
Im not sure if what Im doing is even correct. Like I said I just want the data being snapshotted for each marker to be shown to that specific marker.

So I Managed to solve the issue.
I added
boardMarker.title = key
inside the loop where the Marker is being created.
I then wrote this section of code
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
let markerTitle = marker.title as! String
let Markerview: infoWindow = UIView.fromNib()
filteredStruct = arrAllMarkers.filter{$0.key.range(of: markerTitle) != nil}
print(filteredStruct)
Markerview.titleLbl.text = filteredStruct[0].title
Markerview.ratingLbl.text = filteredStruct[0].rating
Markerview.difficultyLbl.text = filteredStruct[0].diff
transferKey = markerTitle
Markerview.alpha = 0.8
Markerview.layer.cornerRadius = 30
print(transferKey)
return Markerview
}
and it works perfectly!

Related

Eureka Swift - set value of LocationRow

I've got a form where a user can pick from a number of objects that includes co-ordinate data, which I want to load into a LocationRow.
I have tried several different ways to try and set the Location Row value, but it either crashes (unexpectedly found nil while unwrapping an optional Value) or doesn't reload the table with the correct data. i.e. https://i.imgur.com/2XkeHbu.png
My LocationRow eureka code:
$0.rowRight = LocationRow(){
$0.title = "Location"
$0.tag = "location"
if let page = selectedPage {
if let pageLocationLatitude = page.locationLatitude.value,
let pageLocationLongutude = page.locationLongitude.value {
print("testing for row update")
$0.value = CLLocation(latitude: pageLocationLatitude, longitude: pageLocationLongutude)
}
}
}
and the function that is called when I want to update the LocationRow
private func setSelectedPage(pageName : String) {
print("setting location of page: \(pageName)")
if pageName == username {
return
}
selectedPage = userPages?.filter("name == \"\(pageName)\"").first
if let locationLongitude = selectedPage?.locationLongitude.value,
let locationLatitude = selectedPage?.locationLatitude.value {
print("lat and lon: \(locationLatitude) \(locationLongitude)")
/*PURELY FOR TESTING
let titleRow = self.form.rowBy(tag: "title") as! TextRow
titleRow.value = "TEST WORKS OK"
titleRow.updateCell()
PURELY FOR TESTING */
let locationRow = self.form.rowBy(tag: "location") as! LocationRow
locationRow.value = CLLocation(latitude: locationLatitude, longitude: locationLongitude)
self.form.rowBy(tag: "location")?.updateCell()
}
self.tableView.reloadData()
}
From your code, I can see that you are putting this location row in a SplitRow:
// rowRight is a property of SplitRow
$0.rowRight = LocationRow(){
Therefore, the form doesn't really know about the location row. It only knows about the split row. You should get the split row using its tag first, then access rowRight.
// use the tag of your split row here!
let splitRow = self.form.rowBy(tag: "splitRow")
as! SplitRow<SomeRow, LocationRow> // replace SomeRow with the type of row on the left of the split row
let locationRow = splitRow.rowRight
locationRow.value = CLLocation(latitude: locationLatitude, longitude: locationLongitude)
locationRow.updateCell()

How to update multiple location without clearing GoogleMap

I have load couple of users in map with clustering and now I want to update the users location as per the users new location which I receive from server.
I'm able to do that by clearing the map and load new users data from server but it looks like markers are jumping and it not looks proper.
Is there any way to update the marker locations without clearing the GoogleMap?
Here is the link of my question : Google Map with Cluster and Custom view marker lagging too much while zoomIn and zoomOut
Reference Screen
if some one is moved from his location then how can I update his/her location once I receive updated data from server. (Without clearing the map)
My Code
func setMarkers() {
for i in 0..<SharedData.sharedInstance.allFriends.count {
let marker = GMSMarker()
let friend = SharedData.sharedInstance.allFriends[i]
marker.position = CLLocationCoordinate2D.init(latitude: friend.user_details.latitude , longitude: friend.user_details.longitude)
marker.accessibilityHint = String(i)
marker.icon = #imageLiteral(resourceName: "trans")
marker.tracksViewChanges = true
marker.map = mapView
arrMarkers.append(marker)
self.generatePOIItems(String(format: "%d", i), position: marker.position, icon: nil, friend: friend, userIndex: i)
}
clusterManager.cluster()
clusterManager.setDelegate(self, mapDelegate: self)
}
func updateMarkers() {
for i in 0..<arrMarkers.count {
let marker = arrMarkers[i]
let friend = SharedData.sharedInstance.allFriends[i]
marker.position = CLLocationCoordinate2D.init(latitude: friend.user_details.latitude , longitude: friend.user_details.longitude)
marker.accessibilityHint = String(i)
marker.icon = #imageLiteral(resourceName: "trans")
marker.tracksViewChanges = true
marker.map = mapView
}
self.defaultCamera(latitude: SharedData.sharedInstance.userLocation.coordinate.latitude, longitude: SharedData.sharedInstance.userLocation.coordinate.longitude)
}
EDIT
func generatePOIItems(_ accessibilityLabel: String, position: CLLocationCoordinate2D, icon: UIImage?, friend: WallBeeppClass, userIndex: Int) {
let name = "Item \(accessibilityLabel)"
let item = POIItem(position: CLLocationCoordinate2DMake(position.latitude, position.longitude), name: name, friend: friend, userIndex: userIndex)
clusterManager.add(item)
}
func updateMarkers() {
for i in 0..<arrMarkers.count {
let marker = arrMarkers[i]
let friend = SharedData.sharedInstance.allFriends[i]
CATransaction.begin()
CATransaction.setAnimationDuration(1.0)
marker.position = CLLocationCoordinate2D.init(latitude: friend.user_details.latitude , longitude: friend.user_details.longitude)
CATransaction.commit()
}
}
EDIT 1
If I change some users location from backend and when I got users new location then I update the marker position using above code but the issue is that new location users are still located at old location. and if I clear & redraw the users data then it works fine.
EDIT 2
func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) {
marker.groundAnchor = CGPoint(x: 0.1, y: 0.45)
if let markerData = (marker.userData as? POIItem) {
let infoWindow = Bundle.main.loadNibNamed("InitialMapInfoView", owner: self, options: nil)?.first as! InitialMapInfoView
infoWindow.imgUser.sd_setImage(with: URL(string: markerData.friend.user_details.user_photo_small), placeholderImage: #imageLiteral(resourceName: "User_profile"), options: .highPriority, completed: nil)
if !markerData.friend.user_details.isUserOnline {
infoWindow.imgCar.image = UIImage.init(named: "small_inactive_" + markerData.friend.user_details.car_personality_name)
}
else {
infoWindow.imgCar.image = UIImage.init(named: "small_" + markerData.friend.user_details.car_personality_name)
}
if markerData.friend.user_details.user_id == 88 {
print("Will Rendrer Marker: \(markerData.friend.user_details.latitude)")
print("Will Rendrer Marker: \(markerData.friend.user_details.longitude)")
}
infoWindow.lblName.text = markerData.friend.user_details.name
infoWindow.btnImgVW.tag = markerData.userIndex
infoWindow.btnImgVW.addTarget(self, action: #selector(btnUserTapped(_:)), for: .touchUpInside)
marker.accessibilityHint = String(markerData.userIndex)
marker.iconView = infoWindow
marker.tracksViewChanges = false
}
Please guide me to do this.
you can subclass GMSMarker, add id of your objects, then get markers by object id you got from server and update position. Here is some code to explain what I mean
class MyMarker: GMSMarker {
var id: String? = nil
}
add id to your marker
func setMarkers() {
let marker = MyMarker()
let friend = SharedData.sharedInstance.allFriends[I]
marker.id = friend.id
than update by id
for friend in SharedData.sharedInstance.allFriends {
guard
let marker = array.first { $0.id == friend.id }
else { contiunue }
marker.position = CLLocationCoordinate2D.init(latitude: friend.user_details.latitude , longitude: friend.user_details.longitude)
}
don't add marker to map again, just change it's position

Button is Showing GMSMarkers but isn't Hiding it, How do I get it to do both

Im creating an app that shows different locations. Currently when a button is pressed the car locations pop up on the map, however I want to then hide those shown markers if that same button is pressed again.
This is the function that takes a snapshot of my database from firebase, it then inserts the GMSMarker into the location.
func showCarIcon() {
ref = Database.database().reference()
ref.child("location").observe(.childAdded) { (snapshot:DataSnapshot) in
if let dict = snapshot.value as? [String:AnyObject] {
if dict["Activity"] as! String == "Car" {
let longitude = dict["Longitude"] as! String
let lattitude = dict["Lattitude"] as! String
let title = dict["Title"] as! String
self.carIconArray.insert(coordinate(carLat: lattitude, carLng: longitude), at: 0)
let n = self.carIconArray.count
let heightWidth = self.mapView.frame.height
for marker in 1...n {
let carMarker = GMSMarker()
let carIconView = UIImage(named: "carPin")
let image = carIconView
let location = CLLocationCoordinate2D(latitude: Double(lattitude)!, longitude: Double(longitude)!)
carMarker.position = location
carMarker.icon = image
carMarker.title = title
carMarker.icon = self.image(image!, scaledToSize: CGSize(width: heightWidth/6, height: heightWidth/6))
func displayIt() {
if self.carNumber == "1" {
carMarker.map = self.mapView
} else {
carMarker.map = nil
}
}
displayIt()
}
}
}
}
}
So this is the action function for when button is pressed.
var carNumber = String()
#IBAction func showCar(_ sender: Any) {
if motorisedVehicleButtonActive {
motorisedVehicleButton.setImage(UIImage(named: "carO"), for: .normal)
carNumber = "1"
} else {
motorisedVehicleButton.setImage(UIImage(named: "car"), for: .normal)
carNumber = "0"
}
print(carNumber)
motorisedVehicleButtonActive = !motorisedVehicleButtonActive
showCarIcon()
}
Let me explain what is issue with your code.
You are creating new marker every time when button press. So, new marker have different object id than older.
When you try to remove it, it will not works just because of it's different marker than you placed on map.
So you need to store marker in array and on remove time, get icon from array and remove it from map.
First you need to create array of GMSMarker, because you have to store every marker which is placed on map.
So, write following line of code at top of your class.
var arrCarMarkers = [GMSMarker]()
Then after, store every marker in this array which are you placing on map.
So, update your code as follow:
func displayIt() {
if self.carNumber == "1" {
carMarker.map = self.mapView
arrCarMarkers.append(carMarker) // Here is store marker in array
} else {
carMarker.map = nil
}
}
Now, you have all marker which are placed on map. So when you want to remove these markers just update your code as follow:
#IBAction func showCar(_ sender: Any) {
if motorisedVehicleButtonActive {
motorisedVehicleButton.setImage(UIImage(named: "carO"), for: .normal)
carNumber = "1"
showCarIcon()
} else {
motorisedVehicleButton.setImage(UIImage(named: "car"), for: .normal)
carNumber = "0"
self.arrCarMarkers.forEach { $0.map = nil }
}
print(carNumber)
motorisedVehicleButtonActive = !motorisedVehicleButtonActive
}
Above code will remove all markers from map.
I hope this will works for you.

Map with multiple markers displaying only one marker when there are many in the list when put in the dispatch queue

I have an array of lat lon where Im trying to put all the lat long with markers only 1 marker is showing up on the map. Please help
for item in json {
//print(item["price"])
if let vendor = item["vendor"] as? [String:Any],
let lat = vendor["latitude"] as? Double,
let lon = vendor["longitude"] as? Double,
let termsandcondi = item["termsAndConditions"] as? String,
let pre = item["price"] as? Int ,
let name = item["name"] as? String, !name.isEmpty {
//print(termsandcondi)
//print(pre)
self.locationManager.delegate = self
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
let data = ["name":name,"latitude":lat,"longitude":lon,"termsAndConditions":termsandcondi,"price":pre] as! [String : AnyObject]
//print("getting here")
self.myArray.append(data)
DispatchQueue.main.async {
print("Coming here !! Dispatch Queue")
let camera = GMSCameraPosition.camera(withLatitude:12.9716, longitude:77.5946, zoom: 10.0)
let subView = GMSMapView.map(withFrame: CGRect(x: 0, y: 0, width: self.mapView.frame.size.width, height: self.mapView.frame.size.height), camera: camera)
self.nameDeal.text = name as String?
self.pric.text = String(describing: pre)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude:lat, longitude:lon)
marker.title = name
marker.map = self.mapView
//marker.map = self.mapView
}
This method will get you post multiple pins on map.
Put this in a mehod and use
func preparingMap(){
//Filtered data is in array of key values that contains lat long
guard let _filteredData = filteredData else { return }
//Converting lat long to double
var latitude = filteredData?.first?.lATITUDE
var longitude = filteredData?.first?.lONGITUDE
for pins in _filteredData{
let position = CLLocationCoordinate2D(latitude: CLLocationDegrees(Float(latitude)), longitude: CLLocationDegrees(Float(longitude)))
let marker = GMSMarker(position: position)
marker.icon = UIImage(named: "map-location-pin")
marker.map = self.mapView
marker.userData = pins.iD
}
}

Show marker address (street-Address) with clicking in swift

I have a latitude and longitude location of marker in google maps that I want to convert to the location name String in Swift. What is the best way to do this?
i want to show markers' location address and i don't know how to do it .
here is my code that i used to add marker and get latitude and longitude:
func mapView(mapView: GMSMapView, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
if counterMarker < 2
{
counterMarker += 1
let marker = GMSMarker(position: coordinate)
marker.appearAnimation = kGMSMarkerAnimationPop
marker.map = mapView
marker.position.latitude = coordinate.latitude
marker.position.longitude = coordinate.longitude
print(marker.position.latitude)
print(marker.position.longitude)
}
}
func mapView(mapView: GMSMapView, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
if counterMarker < 2
{
counterMarker += 1
let marker = GMSMarker(position: coordinate)
marker.appearAnimation = kGMSMarkerAnimationPop
marker.map = mapView
marker.position.latitude = coordinate.latitude
marker.position.longitude = coordinate.longitude
self.getAddressForLatLng(String(format: "%#",marker.position.latitude), longitude:String(format: "%#",marker.position.longitude)
}
}
func getAddressForLatLng(latitude: String, longitude: String) {
let url = NSURL(string: "https://maps.googleapis.com/maps/api/geocode/json?latlng=\(latitude),\(longitude)&key=YOUR-APIKEY")
let data = NSData(contentsOfURL: url!)
let json = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary
if let result = json["results"] as? NSArray {
if let address = result[0]["address_components"] as? NSArray {
let number = address[0]["short_name"] as! String
let street = address[1]["short_name"] as! String
let city = address[2]["short_name"] as! String
let state = address[4]["short_name"] as! String
let zip = address[6]["short_name"] as! String
print("\n\(number) \(street), \(city), \(state) \(zip) \(address)")
}
}
}