I'm using Google Maps SDK for iOS (version 2.1.1) with Xcode 8. I added a UIView and set its class to GMSMapView and linked up with an IBOutlet called mapView.
double bearing;
int zoomLevel;
- (void)viewDidLoad {
[super viewDidLoad];
bearing = 30;
zoomLevel = 20;
_locationManager = [[CLLocationManager alloc] init];
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
_locationManager.delegate = self;
[_locationManager startUpdatingLocation];
if([CLLocationManager headingAvailable]) {
_locationManager.headingFilter = 5;
[_locationManager startUpdatingHeading];
}
mapView.myLocationEnabled = YES;
mapView.settings.tiltGestures = NO;
mapView.settings.scrollGestures = NO;
// obtain my position
CLLocation *myLocation = mapView.myLocation;
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:myLocation.coordinate.latitude
longitude:myLocation.coordinate.longitude
zoom:zoomLevel
bearing:bearing
viewingAngle:45];
mapView.camera = camera;
}
The View Controller uses 2 delegates : CLLocationManagerDelegate and GMSMapViewDelegate.
Updating map location is not a problem, but when I rotate the map, since the bearing value has not changed at all, once the location is updated, the bearing is reset and cancelled the rotation. How can I update the bearing after I rotate the map?
Here is the didUpdateLocations: delegate function:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *myLocation = [locations lastObject];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:myLocation.coordinate.latitude
longitude:myLocation.coordinate.longitude
zoom:zoomLevel
bearing:bearing
viewingAngle:45];
[mapView animateToCameraPosition:camera];
}
My idea is to rotate the map exactly like the mobile game PokemonGO.
Related
I am using Google Maps SDK to get the current location. My doubt is, how to do location updates using the delegate methods using Google Maps SDK. Is there any delegate methods for getting the current location and location updates?
#implementation MyLocationViewController {
GMSMapView *mapView_;
}
- (void)viewDidLoad {
[super viewDidLoad];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868 longitude:151.2086 zoom:12];
mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
mapView_.settings.compassButton = YES;
mapView_.settings.myLocationButton = YES;
// Listen to the myLocation property of GMSMapView.
[mapView_ addObserver:self forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew context:NULL];
self.view = mapView_;
// Ask for My Location data after the map has already been added to the UI.
dispatch_async(dispatch_get_main_queue(), ^{
mapView_.myLocationEnabled = YES;
});
}
In order to get current location on iOS , refer to following link:
How can I get current location from user in iOS
You can use CLLocationManager delegate methods to update location and set the location to the map.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
This delegate method will update the location. Inside the method, you can set the map view to the coordinates received.
_currentLocation = [locations lastObject];
CLLocationCoordinate2D target =
CLLocationCoordinate2DMake(_currentLocation.coordinate.latitude, _currentLocation(This is the current location of the user).coordinate.longitude);
_googleMap.camera = [GMSCameraPosition cameraWithTarget:target zoom:16];
I am building an iOS application that display a POI in a MapView, but firstly I can display the map, and with iOS8 this is begin a problem.
I read a lot question in this site, but none run on my app even if the code seems right.
I entered into myapplicationTest-info.plist the following code
<key>NSLocationAlwaysUsageDescription</key>
And the code in the file.m is this:
#import "MapViewController.h"
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
#interface MapViewController ()
#end
#implementation MapViewController
#synthesize mapView = _mapView ;
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
self.locationManager.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
if (IS_OS_8_OR_LATER) {
//[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
self.mapView.showsUserLocation = YES;
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
self.locationManager.distanceFilter = kCLDistanceFilterNone; //Whenever we move
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
NSLog(#"%#", [self deviceLocation]);
//View Area
MKCoordinateRegion region = { { 0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = self.locationManager.location.coordinate.latitude;
region.center.longitude = self.locationManager.location.coordinate.longitude;
region.span.longitudeDelta = 0.005f;
region.span.longitudeDelta = 0.005f;
[mapView setRegion:region animated:YES];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
- (NSString *)deviceLocation {
return [NSString stringWithFormat:#"latitude: %f longitude: %f", self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceLat {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.latitude];
}
- (NSString *)deviceLon {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceAlt {
return [NSString stringWithFormat:#"%f", self.locationManager.location.altitude];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Where is the mistake?
Why it doesn't run?
You need to provide a value for NSLocationAlwaysUsageDescription key which is the string that describes why your app wants to use location services -
For example -
<key>NSLocationAlwaysUsageDescription</key>
<string>FindMeDonuts will use your location to identify nearby donut shops</string>
Also, rather than checking the iOS version, it is better to check if CLLocationManager responds to the authorisation selector -
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
finally, this won't stop your map from updating, but it doesn't make sense - you are assigning a delegate to your CLLocationManager before you allocate and initialise it.
You should say -
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate=self;
I don't know if i understand your problem.
if your problem is about the map is not show, you need to set frame of your map.
self.mapView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
hope i could help you
The best way is to use the -locationManager:didUpdateLocations method provided by CLLocationManagerDelegate.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
[self.locationManager stopUpdatingLocation];
// Move this line here
self.mapView.showsUserLocation = YES;
}
After calling [self.locationManager startUpdatingLocation] in ViewDidLoad, you shouldn't set self.mapView.showsUserLocation to YES yet as permission to use location services is not yet approved. Use the delegate to wait/get a location update from the system before setting self.mapView.showsUserLocation to YES.
You also need to enable location services
if([CLLocationManager resolveClassMethod:#selector(locationServicesEnabled)]) {
[CLLocationManager locationServicesEnabled];
}
I dropped the maps from iOS and switched to google maps. Now it shows my position but it doesn't load the map. It is gray / yellow with in the bottom left Google.
This is my implementation:
#import <CoreLocation/CoreLocation.h>
#interface GoogleMapViewController ()
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
#implementation GoogleMapViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Create a GMSCameraPosition that tells the map to display the
// coordinate -33.86,151.20 at zoom level 6.
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.86
longitude:151.20
zoom:6];
_mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
_mapView.myLocationEnabled = YES;
self.view = _mapView;
[self initLocationManager];
// Creates a marker in the center of the map.
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(-33.86, 151.20);
marker.title = #"Sydney";
marker.snippet = #"Australia";
marker.map = _mapView;
}
- (void) initLocationManager
{
self.locationManager = [[CLLocationManager alloc] init] ;
self.locationManager.delegate = (id)self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation ;
[self.locationManager setDistanceFilter:10.0f] ;
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(#"New locations");
[self.locationManager stopUpdatingLocation];
_mapView.camera = [GMSCameraPosition cameraWithTarget:newLocation.coordinate
zoom:6];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
This is basically the tutorial demo app from Google Dev page, and I'm not sure why it's not loading the map.
This is what I get:
I found the problem. You need to set the initial camera zoom level on 1 and then zoom in on your current location. That way you can still zoom out and have the whole map available.
If you take a zoomlevel 14 as initial, google maps doesn't load the rest of the map I think.
I am currently working with Google Maps API in my project. I am trying to set the default camera/zoom to the users location. I do this:
#implementation ViewController{
GMSMapView *mapView_;
}
#synthesize currentLatitude,currentLongitude;
- (void)viewDidLoad
{
[super viewDidLoad];
mapView_.settings.myLocationButton = YES;
mapView_.myLocationEnabled = YES;
}
- (void)loadView{
CLLocation *myLocation = mapView_.myLocation;
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(myLocation.coordinate.latitude, myLocation.coordinate.longitude);
marker.title = #"Current Location";
marker.map = mapView_;
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:myLocation.coordinate.latitude
longitude:myLocation.coordinate.longitude
zoom:6];
mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.view = mapView_;
NSLog(#"%f, %f", myLocation.coordinate.latitude, myLocation.coordinate.longitude);
}
However, it does not work, since when I do
NSLog(#"%f, %f", myLocation.coordinate.latitude, myLocation.coordinate.longitude);
it returns 0, 0, and it does not give the current location coordinates. How can I properly get the user's coordinates?
.h
#import <CoreLocation/CoreLocation.h>
#property(nonatomic,retain) CLLocationManager *locationManager;
.m
- (NSString *)deviceLocation
{
NSString *theLocation = [NSString stringWithFormat:#"latitude: %f longitude: %f", locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude];
return theLocation;
}
- (void)viewDidLoad
{
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
}
answered here.
When an app first starts it may not yet know your location, as it usually takes a while for the GPS device to lock on to your location (if it has just been started), and especially if this is the first time the application has been run, and so the user hasn't yet answered the prompt to give the app access to their location. Also it seems like mapView.myLocation is always empty (either nil or has coordinates 0,0) when the map view has just been created.
So you will need to wait until the user's location is known, and then update the camera position.
One way might be using the code at how to get current location in google map sdk in iphone as suggested by Puneet, but note that the sample code there is missing the details of setting up the location manager (like setting the location manager's delegate), which might be why it didn't work for you.
Another option could be to use KVO on mapView.myLocation, as described here: about positioning myself,some problems
By the way in your sample code you are accessing mapView.myLocation before you create the mapView, and so the location would always be nil anyway.
I just Downloaded the new GoogleMap SDK Demo for iOS. Here is what I have seen from the source code that how the "Current Location" is achieved via KVO.
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#import "SDKDemos/Samples/MyLocationViewController.h"
#import <GoogleMaps/GoogleMaps.h>
#implementation MyLocationViewController {
GMSMapView *mapView_;
BOOL firstLocationUpdate_;
}
- (void)viewDidLoad {
[super viewDidLoad];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868
longitude:151.2086
zoom:12];
mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
mapView_.settings.compassButton = YES;
mapView_.settings.myLocationButton = YES;
// Listen to the myLocation property of GMSMapView.
[mapView_ addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
self.view = mapView_;
// Ask for My Location data after the map has already been added to the UI.
dispatch_async(dispatch_get_main_queue(), ^{
mapView_.myLocationEnabled = YES;
});
}
- (void)dealloc {
[mapView_ removeObserver:self
forKeyPath:#"myLocation"
context:NULL];
}
#pragma mark - KVO updates
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if (!firstLocationUpdate_) {
// If the first location update has not yet been recieved, then jump to that
// location.
firstLocationUpdate_ = YES;
CLLocation *location = [change objectForKey:NSKeyValueChangeNewKey];
mapView_.camera = [GMSCameraPosition cameraWithTarget:location.coordinate
zoom:14];
}
}
#end
Hope it can help you.
Just in case anyone wants DrDev's excellent answer in Swift 3:
var locationManager: CLLocationManager?
func deviceLocation() -> String {
let theLocation: String = "latitude: \(locationManager.location.coordinate.latitude) longitude: \(locationManager.location.coordinate.longitude)"
return theLocation
}
func viewDidLoad() {
locationManager = CLLocationManager()
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
// 100 m
locationManager.startUpdatingLocation()
}
I'm trying to show a map in my application, it works on my simulator and on my ipod touch 4g.
But I always get an error on my iPhone and I don't know why this happens.
Maybe you can explain me why it fails.
The error is:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid Region <center:nan, nan span:nan, nan>'
I already searched for solutions on google and stackoverflow but it seems that nobody has this problem.
Thats my code:
//setup mapview
mapView.delegate = self;
mapView.showsUserLocation = YES;
//set up core location
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
//Set up zoom location
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = locationManager.location.coordinate.latitude;
zoomLocation.longitude= locationManager.location.coordinate.longitude;
debug(#"Location: %f und %f",locationManager.location.coordinate.latitude,locationManager.location.coordinate.longitude);
//zoom to location
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion];
[mapView setRegion:adjustedRegion animated:YES];
As I said, it works on iPod and simulator, but not on iPhone.
Hope you can help me
SOLUTION:
I used the locationManager too early, so the app crashed. Now I used it this way:
- (void)viewDidLoad {
[super viewDidLoad];
//setup mapview
mapView.delegate = self;
mapView.showsUserLocation = YES;
//set up core location
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
//Set up zoom location
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = newLocation.coordinate.latitude;
zoomLocation.longitude= newLocation.coordinate.longitude;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion];
[mapView setRegion:adjustedRegion animated:YES];
debug(#"Location: %f und %f",newLocation.coordinate.latitude,newLocation.coordinate.longitude);
}
Don't know if this way is 100% correct, but it works.