How do i enabled a Google Maps button in a cell? - ios

In a custom tableViewCell , I connect a View which is a google map class to the custom class
However it seems that these line of code doesn't run in the custom cell that I created
This cell is part of a tableView, I tried to instantiate this cell for example var gmapsCell = GMapTableViewCell in the viewDidLoad of the TableView but it seems it will always returns nil
So I change my approach to below codes
import UIKit
import GoogleMaps
class GMapTableViewCell: UITableViewCell, GMSMapViewDelegate {
let locationManager = CLLocationManager()
#IBOutlet var mapView: GMSMapView!
override func awakeFromNib() {
super.awakeFromNib()
locationManager.requestAlwaysAuthorization()
// For use in foreground
locationManager.requestWhenInUseAuthorization()
mapView.delegate = self
mapView.settings.myLocationButton = true
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension GMapTableViewCell: CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedWhenInUse {
locationManager.startUpdatingLocation()
mapView.myLocationEnabled = true
mapView.settings.myLocationButton = true
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
locationManager.stopUpdatingLocation()
}
}
}
The problem right now is that
override func awakeFromNib() {
super.awakeFromNib()
locationManager.requestAlwaysAuthorization()
// For use in foreground
locationManager.requestWhenInUseAuthorization()
mapView.delegate = self
mapView.settings.myLocationButton = true
}
This will never run. My goal is simply to get to the device's current location. Are there any equivalent of viewDidLoad for custom cell?

You need to add "NSLocationWhenInUseUsageDescription" key as a string type in info.plist for the location Manager to start updating locations.

All that code inside awakeNib() should be written in tableView:cellForRowAtIndexPath.
Set all the delegates there.
It will work fine then.

Related

Unrecognized selector sent to instance.. 'NSInvalidArgumentException' for MapView delegate

Swift 4/Google Maps.
The crash I get is..
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[UIView setDelegate:]:
unrecognized selector sent to instance 0x7fa1eb50d7e0'
Yes, I know there are a lot of threads on this, but looking through them has not helped me. I have debugged enough where I have a suspect, but do not know exactly how to resolve.
Here's the git repo
Some detail.. The MapViewController has three UIViews.
MapViewController
Main View (default one that comes with the controller)
-- Menu (sub view of Main View)
-- Map (sub view of Main View)
I believe I've narrowed down the crash to the statement
self.mapView.delegate = self
Here's most of the code for the MapViewController.
import UIKit
import GoogleMaps
import FirebaseDatabase
class MapViewController: UIViewController, GMSMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet var mapView: GMSMapView!
var locationOfInterestMarker = GMSMarker()
var userMarker = GMSMarker()
var locationManager = CLLocationManager()
let zoom:Float = 15
let locationOfInterestImage:String = "hhouseicon"
let userMarkerImage:String = "witchicon"
override func viewDidLoad() {
super.viewDidLoad()
self.getLocations()
self.locationManager.delegate = self
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startMonitoringSignificantLocationChanges()
/**
The next line causes crash. I believe I need to set the delegate to something other than self. Set the delegate to the View named Map. However I'm not sure about the actual code for that.
**/
self.mapView.delegate = self //Crashes
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
guard status == .authorizedWhenInUse else {
return
}
self.locationManager.startUpdatingLocation()
self.mapView.isMyLocationEnabled = true
self.mapView.settings.myLocationButton = true
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.first else {
return
}
self.locationManager.stopUpdatingLocation()
self.mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
self.placeMarker(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude, marker: self.userMarker, imageName: userMarkerImage)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if let destination = segue.destination as? LocationDetialViewController {
destination.coordinate = locationManager.location?.coordinate
} else {
return
}
} . . .
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
performSegue(withIdentifier: "locationDetailSegue", sender: self)
return false
}
}//MapViewController
After looking at your code and storyboard.
I can see that you have connected the
#IBOutlet var mapView: GMSMapView!
To the parent view not to actual GMSMapView so please recheck the IBOutlet connections.
I had a similar issue, but the problem was i didn't inherit the module from target

Google map loading issue iOS

I have integrated GoogleMap using pod in my project but map is not loading. When I make my mapViewController as a initial ViewController then its working fine.
But when I push or present MapViewController then its showing me the blank screen.
I am using XCode 9.1, my project deployment Target is 9.0 and Google Maps SDK for iOS version: 2.5.30219.0.
Thanks in Advance.
Here is my MapViewController code:
import UIKit
import GoogleMaps
class MapViewController: UIViewController {
#IBOutlet weak var mapView: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
let camera = GMSCameraPosition.camera(withTarget: CLLocationCoordinate2DMake(18.486726, 73.798394), zoom: 10)
mapView.camera = camera
}
}
Console Log:
CoreData: annotation: Failed to load optimized model at path
/Users/pritamsing.salunkhe/Library/Developer/CoreSimulator/Devices/6DD7C0EA-320F-4E99-BEC9-672046198800/data/Containers/Bundle/Application/04CC747F-5B2D-4588-883A-E814D4EE0769/HimmatPlus.app/GoogleMaps.bundle/GMSCacheStorage.momd/StorageWithTileVersionID.omo
Don't use IBOutlet for googleMap in Storyboard & also Don't set subclass for GMSMapView.
implement your map by programmatically. Its will boost your Map UI faster
/// Google MapView
var mapView: GMSMapView!
self.mapView = GMSMapView(frame: CGRect(x: 0, y: 64, width: self.currentDeviceSize.width, height: self.bottomBgView.frame.minY - 64))
// self.mapView.autoresizingMask = [.flexibleBottomMargin, .flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin]
self.mapView.settings.allowScrollGesturesDuringRotateOrZoom = true
// self.mapView.settings.myLocationButton = true //Enable My location button
// self.mapView.isTrafficEnabled = true //Enable traffic
// self.mapView.isBuildingsEnabled = true // Building Enable
// self.mapView.isMyLocationEnabled = true //My location Enabled
// let containerView: GMSMapView = self.mapView
self.view.addSubview(self.mapView)
Try with the proper implementation of Google map.
#IBOutlet weak var mapView: GMSMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
self.configureMap()
}
func configureMap(){
mapView.delegate = self
//Check for Location Services
if (CLLocationManager.locationServicesEnabled()) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.requestWhenInUseAuthorization()
}
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
}
}
MapView Delegate method
//MARK:- MapView delegate
extension YourViewControllerName: GMSMapViewDelegate, CLLocationManagerDelegate{
//Location Manager delegates
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let camera = GMSCameraPosition.camera(withLatitude: (location?.coordinate.latitude)!, longitude: (location?.coordinate.longitude)!, zoom: 12.0)
self.mapView?.animate(to: camera)
// To stop updating the location again
self.locationManager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("error description:\(error.localizedDescription)")
}
}
Key In plist file.
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your custom message.</string>

Can't display user current location Mapbox iOS API

I want to display user's current location immediately after they open the app. I use Mapbox iOS SDK. But it doesn't work at all. I don't know what's wrong. I can only see an irrelevant map after I open it.
import UIKit
import Mapbox
import CoreLocation
class ViewController: UIViewController, MGLMapViewDelegate, CLLocationManagerDelegate
{
#IBOutlet weak var mapView: MGLMapView!
let locationManager = CLLocationManager()
override func viewDidLoad()
{
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last
let mapView = MGLMapView(frame: view.bounds)
mapView.userTrackingMode = .Follow
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
mapView.setCenterCoordinate(center, zoomLevel: 15, animated: true)
view.addSubview(mapView)
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print ("Errors:" + error.localizedDescription)
}
}
I think the issue might be the iOS Simulator. When you run an app on the simulator, it doesn't simulate your location until you tell it to.
If you look at your Xcode, you'll see a navigate button at the bottom.
Try changing the location to something, and it should show up :)

How to display sub view or button on top of Google maps Xcode

I was trying to add a button on top of Google maps. i tried everything i could but no help can anyone help me.. in Xcode preview it shows on top but after running the app it come below google map.
Picture after running app
How it looks in XCODE
CODE OF MAP
import UIKit
import GoogleMaps
class HomeViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBAction func refreshLocation(sender: AnyObject) {
locationManager.startUpdatingLocation()
}
#IBOutlet weak var gMapView: GMSMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
self.scrollView.contentSize=CGSizeMake(320, 700)
let camera = GMSCameraPosition.cameraWithLatitude(15.4989, longitude: 73.8278, zoom: 17)
gMapView.camera = camera
gMapView.myLocationEnabled = true
self.view.addSubview(gMapView)
let marker = GMSMarker()
marker.map = self.gMapView
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension HomeViewController {
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == CLAuthorizationStatus.AuthorizedAlways {
locationManager.startUpdatingLocation()
gMapView.myLocationEnabled = true
gMapView.settings.myLocationButton = true
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
gMapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
locationManager.stopUpdatingLocation()
}
}
}
I found the answer
self.view.bringSubviewToFront(self.view_name)
You need to call bringSubviewToFront on the parent view.
Are you using below method? If yes , make sure you are giving frame to mapview so try to give frame as same as you gave in storyboard.
[GMSMapView mapWithFrame:(CGRect) camera:(GMSCameraPosition *)];

Swift Mapkit - Move Away From User Location

I want to display user location and the surrounding area, but I also want to allow the user to pan around the area. Right now if I try to scroll somewhere else on the map it automatically takes me back to the base region with the user at the center. How do I stop this? I want to show the initial view with the user in the center, but I want to be able to scroll around too. Thanks in advance you guys are so helpful!
import UIKit
import MapKit
import CoreLocation
class ViewControllerMain: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var locationManager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.startUpdatingLocation()
mapView.showsUserLocation = true
mapView.delegate = self
let longPress = UILongPressGestureRecognizer(target: self, action: "action:")
longPress.minimumPressDuration = 1.0
mapView.addGestureRecognizer(longPress)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
let regionToZoom = MKCoordinateRegionMake(manager.location.coordinate, MKCoordinateSpanMake(0.01, 0.01))
mapView.setRegion(regionToZoom, animated: true)
}
Your code in didUpdateLocations is resetting the region. You have two options.
Store in an ivar whether or not you have already set the first location. Only if you haven't do you then set the region.
Set a timer that runs for 15 seconds. If the map is moved by the user you reset the timer. When the timer expires you can recenter to the users location.
This will keep the map centred around the user but will enable them to pan around a bit to get some context.
This answer shows how to do it in Objective-C
locationManager.stopUpdatingLocation();
this is all you need at end of locationManager fun, if you are still looking for
This thread had a good example in both Swift and Obj C. Be sure to look for the comment on the answer I've linked to if you use Swift.
After you set that up, use Control Flow within the didUpdateLocations, so that it re-centers the user's location only if the user has not touched the map.
Here is my full code as an example:
#IBOutlet weak var theMap: MKMapView!
// ...
// This var and the three following functions are used to tell if the map moves because of the user.
// This is used in the control flow in didUpdateLocations
private var mapChangedFromUserInteraction = false
private func mapViewRegionDidChangeFromUserInteraction() -> Bool {
let view: UIView = self.theMap.subviews[0] as UIView
// Look through gesture recognizers to determine whether this region change is from user interaction
if let gestureRecognizers = view.gestureRecognizers {
for recognizer in gestureRecognizers {
if( recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Ended ) {
return true
}
}
}
return false
}
func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
mapChangedFromUserInteraction = mapViewRegionDidChangeFromUserInteraction()
if (mapChangedFromUserInteraction) {
// user changed map region
println("user changed map region")
}
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if (mapChangedFromUserInteraction) {
// user changed map region
println("user changed map region")
}
}
// This function is called each time the user moves.
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
// Use Control Flow: if the user has moved the map, then don't re-center.
// NOTE: this is using 'mapChangedFromUserInteraction' from above.
if mapChangedFromUserInteraction == true {
// do nothing, because the user has moved the map.
}
else {
// update on location to re-center on the user.
// set X and Y distances for the span (zoom). This is very zoomed in.
let spanX = 0.0005
let spanY = 0.0005
// Create a region using the user's location, and the zoo.
var newRegion = MKCoordinateRegion(center: theMap.userLocation.coordinate, span: MKCoordinateSpanMake(spanX, spanY))
// set the map to the new region
theMap.setRegion(newRegion, animated: true)
}
}

Resources