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()
}
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'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.
I'm using a google map in iPhone app by objective-c, it is ok and the marker is in a given location. I want when click on a specific location change the marker location to the selected location by clicking the map.
How to do this?
Thanks in advance.
my code:
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:29.964996
longitude:30.939680 zoom:5
bearing:0
viewingAngle:0
];
_mapView = [GMSMapView mapWithFrame:viewOfMap.bounds camera:camera];
_mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth|
UIViewAutoresizingFlexibleHeight;
[_mapView addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
[viewOfMap addSubview:_mapView];
dispatch_async(dispatch_get_main_queue(), ^{
//_mapView.myLocationEnabled = YES;
_mapView.myLocationEnabled = YES;
});
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(lat, lag);
marker.map = _mapView;
- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker
{
marker.icon=[UIImage imageNamed:#"selectedicon.png"];//selected marker
for (int i=0; i<[markerArray count]; i++)
{
GMSMarker *unselectedMarker=markerArray[i];
//check selected marker and unselected marker position
if(unselectedMarker.position.latitude!=marker.position.latitude && unselectedMarker.position.longitude!=marker.position.longitude)
{
unselectedMarker.icon=[UIImage imageNamed:#"unselectedicon.png"];
}
}
return NO;
}
If I understand your question, you want to tap a location and have a marker move to that location.
Be sure that your view controller implements GMSMapViewDelegateand use the didTapAtCoordinate delegate method. Something like this:
-(void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
[marker setPosition:coordinate];
}
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.
Getting leaks in profiler when google map loads. I have created a very simple View Controller based on google's example code and Im finding I am getting a leak when the map loads. I believe the leak is in the SDK itself. Has anyone come across this problem and found a solution?
basic View Controller
//
// JRCViewController.m
// GoogleMapsInterface
//
// Created by Jake Cunningham on 15/01/2014.
// Copyright (c) 2014 Jake Cunningham. All rights reserved.
//
#import "JRCViewController.h"
#interface JRCViewController (){
BOOL firstLocationUpdate_;
GMSMapView *mapView;
}
#end
#implementation JRCViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868
longitude:151.2086
zoom:6];
mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
[mapView addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
self.view = mapView;
dispatch_async(dispatch_get_main_queue(), ^{
mapView.myLocationEnabled = YES;
});
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (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
I found the reason for the problem. Like you, I thought that their "demo code" was supposed to work as is. Not understanding that this line
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868
longitude:151.2086
zoom:6];
The very first line in the demo was actually the problem.
If you are not in Australia (which is where this location point is)
You result in loading the entire world map (tiles) into the memory of the app, which is wrong!
If you know approximately which continent/country/state your map will be used
or better yet! get the user's location BEFORE you show the map, and load the map at that location.
So your initialization of the map should be this:
CLLocation *location = [self getUserLocation]; //probably from shared prefs, even if its 100 miles away from where the user actually is, is better than loading another continent.
and then your viewDidLoad would look like this
- (void)viewDidLoad
{
[super viewDidLoad];
CLLocation *location = [self getUserLocation]; //<== very important!
// Do any additional setup after loading the view, typically from a nib.
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:location.coordinate.latitude
longitude:location.coordinate.longitude
zoom:15];
mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
[mapView addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
self.view = mapView;
dispatch_async(dispatch_get_main_queue(), ^{
mapView.myLocationEnabled = YES;
});
}
The zoom level also has an effect on this -> the bigger the zoom is, the less tiles you load into the memory.
also I added code in viewWillDisappear (assuming that viewDidLoad will run again when the given ViewController will be needed again)
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self.mapView clear];
[self.mapView removeFromSuperview] ;
self.mapView.delegate = nil;
self.mapView = nil ;
}
This helped my app from having to use 140 MB of ram to just 56!
When app normal is between 40 and 45.