iOS GoogleMaps tiles not shown correctly with GMSSyncTileLayer - ios

I am building an app with a custom map using GoogleMaps tiles and GMSSyncTileLayer class. For some reason the tiles are not rendered as expected. Here one single tile is provided independent of the coordinates (for test purpose). The tiles are 256*256 (produced with MapTiler) and in this example I would expect this one tile being repeated and filling the space. I've tried different layer.tileSize = 1024 produces biggest tiles, 512 and 256 respectively smaller. Clearly I don't understand what is going in here. What would be the correct way of using tiles?
--- Edit ---
See my answer below - it might be that the problem was that I had those tiles in Assets.xcassets folder instead of normal folder. However did not test this as code now moved to MapKit instead.
class MapTileLayer: GMSSyncTileLayer {
override func tileFor(x: UInt, y: UInt, zoom: UInt) -> UIImage? {
// Return one specific 256*256 Map tile
let pathToImage = "MapTilesFolder/14/9370/4516"
if let tile = UIImage(named: pathToImage) {
return tile
} else {
return kGMSTileLayerNoTile
}
}
}
import UIKit
import GoogleMaps
class DetailViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let camera = GMSCameraPosition.camera(withLatitude: 62.545144, longitude: 25.905153, zoom: 16.0)
let mapView = GMSMapView.map(withFrame: self.view.frame, camera: camera)
mapView.mapType = GMSMapViewType.none
view = mapView
let layer = MapTileLayer()
layer.tileSize = 1024
layer.map = mapView
// Creates a marker in the center of the map.
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: 62.545144, longitude: 25.905153)
marker.title = "Marker"
marker.snippet = "Place"
marker.map = mapView
}
}
And the result looks like this both on device and simulator. With smaller tileSize the result is just more of smaller tiles but not covering the whole area.

Could not make Google Maps SDK work and moved to Apple MapKit. Got MapKit working according to example here: Advanced MapKit Tutorial: Custom Tiles. The only change that I needed to do to that example was to change order of lines as explained below (Xcode 11.4):
func setupTileRenderer() {
let overlay = AdventureMapOverlay()
overlay.canReplaceMapContent = true
mapView.add(overlay, level: .aboveLabels) // move this below next line
tileRenderer = MKTileOverlayRenderer(tileOverlay: overlay)
}
The change was that "mapView.addOverlay" line needs to come after "tileRenderer" line. The name of the method "mapView.add" had also changed to "mapView.addOverlay". Now works as expected.
I suspect that my initial problem with GoogleMaps SDK might have to do that I added those tiles in "Assets.xcassets" instead to normal folder as in the example mentioned above. I didn't test this as moved my code completely to use MapKit instead of GoogleMaps.

Related

Is there a way to have InfoWindow open on App load in Google Maps API?

Currently my app opens a custom infowindow when the MapView delegate calls the didTap protocol. This then calls a function which initializes the needed aspects of the infowindow shown below ...
var tappedOverlay : GMSOverlay?
var customInfoWindow : CustomInfoWindow?
var mapView: GMSMapView!
override func viewDidLoad(){
super.viewDidLoad()
self.customInfoWindow = CustomInfoWindow().loadView()
let camera = GMSCameraPosition.camera(withLatitude: 37, longitude: -77, zoom: 16.0)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.delegate = self
self.view = mapView
//this is where i attempt to force a infoWindow to open
tappedOverlay = overlay
initInfoWindow(overlay: overlay)
}
fun initInfoWindow(overlay: GMSOverlay){
mapView.animate(toLocation: position!)
let point = mapView.projection.point(for: position!)
let newPoint = mapView.projection.coordinate(for: point)
let camera = GMSCameraUpdate.setTarget(newPoint)
mapView.animate(with: camera)
let background = UIColor.infoWindowBackground
customInfoWindow?.layer.backgroundColor = background.cgColor
customInfoWindow?.layer.cornerRadius = 8
customInfoWindow?.center = mapView.projection.point(for: position!)
customInfoWindow?.center.y -= 100
customInfoWindow?.CustomWindowLabel.text = overlay.title
customInfoWindow?.CustomWindowSubLabel.lineBreakMode = .byWordWrapping
customInfoWindow?.CustomWindowSubLabel.numberOfLines = 0
mapView.addSubview(customInfoWindow!)
}
func mapView(_ mapView: GMSMapView, didTap Overlay: GMSOverlay){
initInfoWindow(overlay: overlay)
}
Now I would like to have the app automatically open a certain infowindow as soon as it loads.
When I try to manually display the infoWindow on load by calling the function in viewDidLoad(), I have to comment out the mapView.animate(with: camera) line otherwise the map tiles will never load. Someone pointed out to me that the mapView methods have some 'background' information about the overlay when they are called, so I added the tappedOverlay = overlay line, this gets close in that part of the infoWindow is displayed when the app is loaded. However, this and all other 'regular' infoWindows appear without a background and not centered on the point and cannot be interacted with.
The infoWindow's are a subclass of UIView loaded from a XIB file.
The above code is what I thought would be relevant extracted from a larger code base. Let me know if anything needs to be added!
Any help is appreciated!
Maybe this answer will help someone else. The issue was in the mapView.projection functions, they were returning essentially default values. I'm not entirely sure, but it seems when you click on a marker the mapView changes part of the frame = ( 0 0;) variable in the background, so this lead me to change the mapView initialization.
So instead of ...
let camera = GMSCameraPosition.camera(withLatitude: 37, longitude: -77, zoom: 16.0)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
We need ...
let camera = GMSCameraPosition.camera(withLatitude: LAT_OF_YOUR_INFOWINDOW,
longitude: LONG_OF_YOUR_INFOWINDOW,
zoom: 16.0)
mapView = GMSMapView.map(withFrame: self.view.bounds, camera: camera)

Google Maps API for iOS - Marker is not displayed

I'm new to coding for iOS and I wanted to have a Map with a path/way on it in my Swift App. After trying to apply an KML Overlay, which didn't work, I decided to use a polyline. But the polyline wasn't desplayed either, so I tried a Marker, exactly following the tutorial at https://developers.google.com/maps/documentation/ios-sdk/marker, but the marker is also not displayed. What am I doing wrong? Here is my code for the Marker:
import UIKit
import GoogleMaps
class MapViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
GMSServices.provideAPIKey("MY_KEY")
let camera = GMSCameraPosition.camera(withLatitude: 48.194857, longitude: 13.955710, zoom: 17)
let mapView = GMSMapView.map(withFrame: .zero, camera: camera)
mapView.mapType = .satellite
mapView.setMinZoom(17, maxZoom: 19)
view = mapView
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: 13.9553836,longitude: 48.1956954)
marker.title = "Hello World"
marker.map = mapView
// Do any additional setup after loading the view.
}
}
Thank you in advance!
I think the code is okay, but the marker is not visible because it is in another part of the world.
Try to exchange latitude and longitude of your marker
marker.position = CLLocationCoordinate2D(latitude: 13.9553836,longitude: 48.1956954)
Or set a lower zoom to your map

How to pass specific element from array to another view or function? Swift

I'm loading data from server and passing it to an array. This data includes coordinates, text, images etc. Also it contains variable, named "id" (I thought about sorting array for specific id, but not sure if this is a good solution). This data is used to show markers on map.
My task is to show this marker's details on separate view. How to tell this details screen which marker was chosen or how to get specific element from array based on chosen marker?
This is were I create markers:
for element in spots {
let image = UIImage(named: element.type)
let position = CLLocationCoordinate2D(latitude: element.coordinates.latitude, longitude:
element.coordinates.longitude)
marker = GMSMarker(position: position)
marker.icon = image
marker.map = mapView
}
You can use GMS delegate method to check which marker is tapped.
for element in spots {
let image = UIImage(named: element.type)
let position = CLLocationCoordinate2D(latitude: element.coordinates.latitude, longitude:
element.coordinates.longitude)
marker = GMSMarker(position: position)
marker.icon = image
marker.map = mapView
// add the element info to marker userData property
marker.userData = element
}
// function to check if which icon tapped
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
// get the element info from marker
let element = marker.userData
//code to navigate to detail view
}
Hope this will help!
This is a pretty generic question, and there are a lot of ways of passing data between objects in Swift / Cocoa, e.g. segues, delegates, notifications, singleton pattern, or simply just direct initialization with dependency injection or without it:
let separateView = SeparateView()
separateView.marker = marker // Note that you need a var defined in your separate view in order to set it sooner, marker is your marker defined from before
navigationController?.pushViewController(separateView, animated: true)

Swift 4 GoogleMaps add UIToolBar / make map "smaller" to fit other UI elements

Perhaps this is the exact same question as this other post
However, I need a more step by step / tutorial type answer.
I want to add a UIToolBar item at the top of my GoogleMap. But the map takes up the entire view. I've searched everywhere and every tutorial, but I can't figure this very simple thing out. If part of the solution is adding a new swift file and placing the 'GMSMap' code there and then changing the original view controller class - that is fine, but I need just a tiny bit more step by step
I've tried play with "withFrame", however that does not seem to help
import UIKit
import GoogleMaps
class FirstViewController: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate {
var mapView:GMSMapView!
var latitude:Double = 0
var longitude:Double = 0
var zoom:Float = 15
let locationManager = CLLocationManager()
var userLocation:CLLocationCoordinate2D!
override func viewDidLoad() {
super.viewDidLoad()
// Setup simple mapview and camera
let camera = GMSCameraPosition.camera(withLatitude: latitude, longitude: longitude, zoom: zoom)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
self.mapView.delegate = self
UPDATE
Things are somewhat better, but there is still a nagging problem.
I have a new repo here
I added two UIViews inside the default View:UIView and added constraints. The 'Map View is type GMSMapView. And I added a view at the top of the scene 'Button View' with a button. Now my UI looks like I want it.
I also created an IBOutlet for GMSMapView and wired it to 'Map View'.
HOWEVER
The map that is displayed is ignoring the latitude and longitude variables. No matter what I set them to, I always see France and other parts of Western Europe. In the example below, I'm using coordinates for San Francisco
class ViewController: UIViewController, GMSMapViewDelegate {
#IBOutlet weak var mapView:GMSMapView!
var latitude:Double = 37.7749
var longitude:Double = 122.4194
var zoom:Float = 12
override func viewDidLoad() {
super.viewDidLoad()
let camera = GMSCameraPosition.camera(withLatitude: latitude, longitude: longitude, zoom: zoom)
let myGSMMap = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView = myGSMMap
self.mapView.delegate = self
}
}
Images for clarity: https://imgur.com/a/vvmD5 . (the green in the upper portion of the screen is the UIView, and below it you will see the map)
Just write below code in your viewWillAppear()
Self.mapView.camera = GMSCameraPosition.camera(withLatitude: latitude, longitude: longitude, zoom: zoom)
It will move your map camera according to latitude and longitude.
And remove what your write-in viewDidLoad()
Check this http://www.ryanwright.me/cookbook/ios/obj-c/maps/gmap/subview. It might be helpful. You have a detailed explanation given.

Adding marker on Google maps

This may be a repeated question (looked at many answers before writing it), but I am unable to solve it.
I want to simple integrate google maps into my swift app. All is working great except getting that marker to show on the map. I am following google map api docs, but no luck.
Here is the body of the function:
// Do any additional setup after loading the view.
/**Testing Google Maps **/
let camera = GMSCameraPosition.cameraWithLatitude(-33.86,
longitude: 151.20, zoom: 6)
//let mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
googleMapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
let position = CLLocationCoordinate2DMake(10, 10)
let marker = GMSMarker(position: position)
marker.title = "Hello World"
marker.map = googleMapView
This is executing in viewDidLoad(). I get the map to show but its not showing any marker.
Thanks for the help.
This code works for me:
var marker = GMSMarker()
marker.postion = CLLocationCoordinate2DMake(10,10)
marker.title ="ENTER TITLE"
marker.snippet ="ENTER SNIPPET"
marker.map = googleMapView
Hope this helps :)
After long trying and researching, got it to work by tweaking one line to get the same map view in the UIView with type GMSMap:
let camera = GMSCameraPosition.cameraWithLatitude(-33.86,
longitude: 151.20, zoom: 6)
googleMapView.camera = camera //This line
googleMapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
did you set the delegate of mapView in viewDidLoad
mapView.delegate = self
and accept GMSMapViewDelegate protocol in your ViewController like this
class ViewController: UIViewController, GMSMapViewDelegate {
}

Resources