I'm trying to display my Google Map inside a custom UIView instead of in self.view. Currently, my code works fine if I set it to display in self.view; the map is displayed with all applied styles and specified camera. But the minute I try and display it in a custom UIView (self.mapView), the map displays but it's completely empty (ie. no camera set, no markers, nothing). Any idea why this is?
MapViewController.h
#interface MapViewController : ViewController <CLLocationManagerDelegate, GMSMapViewDelegate>
#property (strong, nonatomic) IBOutlet GMSMapView *mapView;
#property (nonatomic, strong) IBOutlet GMSCameraPosition *camera;
MapViewController.m
-(void)viewDidLoad {
self.camera = [GMSCameraPosition cameraWithLatitude:-33.868
longitude:151.2086
zoom:12];
self.mapView = [GMSMapView mapWithFrame:CGRectZero camera:self.camera];
self.mapView.settings.compassButton = YES;
self.mapView.settings.myLocationButton = YES;
[self.mapView addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
[self.view addSubview:_mapView];
NSBundle *mainBundle = [NSBundle mainBundle];
NSURL *styleUrl = [mainBundle URLForResource:#"style" withExtension:#"json"];
NSError *error;
// Set the map style by passing the URL for style.json.
GMSMapStyle *style = [GMSMapStyle styleWithContentsOfFileURL:styleUrl error:&error];
NSLog(#"This is what %#", style);
if (!style) {
NSLog(#"The style definition could not be loaded: %#", error);
} else {
NSLog(#"Style Loaded");
}
self.mapView.mapStyle = style;
dispatch_async(dispatch_get_main_queue(), ^{
self.mapView.myLocationEnabled = YES;
});
}
- (void)dealloc {
[self.mapView removeObserver:self
forKeyPath:#"myLocation"
context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if (!firstLocationUpdate) {
firstLocationUpdate = YES;
CLLocation *location = [change objectForKey:NSKeyValueChangeNewKey];
self.mapView.camera = [GMSCameraPosition cameraWithTarget:location.coordinate
zoom:14];
}
}
Related
I created an iOS project and I implemented didUpdateLocations to get my location in a NSObject. I want to get the longitude and the latitude from the delegate to a UIViewController but the result is always null even to test the addObserver I couldn't. In the bottom there is a sample that I did and it shows my location in the label. I implemented didUpdateLocations in the viewcontroller and without a NSObject Class.
This my code in the NSObject:
#import "GpsModel.h"
#implementation GpsModel{
CLLocation *crnLoc;
}
#synthesize locationManager;
#synthesize longitude;
#synthesize latitude;
- (void) initLocation {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager requestWhenInUseAuthorization];
[locationManager requestAlwaysAuthorization];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
//[self showAlert];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
crnLoc = [locations lastObject];
longitude = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.longitude];
latitude = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.longitude];
}
#end
and this is my ViewController :
#import "GpsViewController.h"
#interface GpsViewController ()
#end
#implementation GpsViewController{
CLLocationManager *locationManager;
}
#synthesize gpsView;
#synthesize gpsModel;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
gpsView = [[GpsView alloc] initWithFrame:CGRectMake(0, 0, widthtScreen, heightScreen)];
[self.view addSubview:gpsView];
gpsModel = [GpsModel new];
[gpsModel initLocation];
gpsView.longitudeLabel.text = gpsModel.longitude;
[gpsView.longitudeLabel addObserver:self forKeyPath:#"text" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
gpsView.latitudeLabel.text = gpsModel.latitude;
[gpsView.latitudeLabel addObserver:self forKeyPath:#"text" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if(object == gpsView.longitudeLabel)
{
NSLog(#"long");
}
if(object == gpsView.latitudeLabel)
{
NSLog(#"lat");
}
}
#end
And this my code without the creation of a NSObject Class :
#interface GpsViewController ()
#end
#implementation GpsViewController{
CLLocationManager *locationManager;
CLLocation *crnLoc;
}
#synthesize gpsView;
#synthesize gpsModel;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
gpsView = [[GpsView alloc] initWithFrame:CGRectMake(0, 0, widthtScreen, heightScreen)];
[self.view addSubview:gpsView];
[self initLocation];
}
- (void) initLocation {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager requestWhenInUseAuthorization];
[locationManager requestAlwaysAuthorization];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
[self showAlert];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
crnLoc = [locations lastObject];
NSLog(#"position long : %#",[NSString stringWithFormat:#"%.8f",crnLoc.coordinate.longitude]);
NSLog(#"position lat : %#",[NSString stringWithFormat:#"%.8f",crnLoc.coordinate.latitude]);
gpsView.longitudeLabel.text = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.longitude];
[gpsView.longitudeLabel addObserver:self forKeyPath:#"text" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
gpsView.latitudeLabel.text = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.latitude];
[gpsView.latitudeLabel addObserver:self forKeyPath:#"text" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if(object == gpsView.longitudeLabel)
{
NSLog(#"observe1");
}
if(object == gpsView.latitudeLabel)
{
NSLog(#"observe2");
}
}
and this is my view that contains 2 labels
#implementation GpsView{
CGFloat _originY;
}
#synthesize longitudeLabel;
#synthesize latitudeLabel;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_originY = 50;
[self _initView];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self _initView];
}
return self;
}
- (void)_initComponents {
longitudeLabel = [[UILabel alloc] init];
latitudeLabel = [[UILabel alloc] init];
}
- (void)_initView {
[self _initComponents];
[self _createComponentView];
}
-(void) _createComponentView {
_originY = [self createLabel:_originY :longitudeLabel :self];
[self addSubview:longitudeLabel];
_originY = [self createLabel:_originY :latitudeLabel :self];
[self addSubview:latitudeLabel];
}
You are observing text in a label, that is set only once in your didLoad method and it will never be updated after the location update. If you want to use observers you should observe your gpsModel instance and latitude/longitude properties in it. And in the observeValueForKeyPath delegate method you should update your text labels.
I want to move the marker on basis of lat,long which i'm getting continously I'm doing this like below...
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations (NSArray<CLLocation *> *)locations
{
CLLocationCoordinate2D coor2D = CLLocationCoordinate2DMake(longitude, latitude);
self.marker.position = coor2D;
}
The method is updating lat long but the markers is not moving why...
In info.plist I have added..
Try this, assuming you have set your delegate:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations (NSArray<CLLocation *> *)locations
{
CLLocationCoordinate2D coor2D = CLLocationCoordinate2DMake(longitude, latitude);
self.marker.position = coor2D;
[self.mapView animateToLocation:coord2D.coordinate]
}
If all you're trying to do is update your current location. You should probably just use KVO for that.
#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
Hi i am beginner in Ios and in my project i am using Google SDK for getting route when user walking or driving along the road
But i am not able to get current location and showing in my x code console 0.0 and 0.0(latitude and longitude values) please help me some one for getting current location
My code is below:-
#import "ViewController.h"
#interface ViewController ()
{
GMSMapView *_mapView;
NSMutableArray *_coordinates;
LRouteController *_routeController;
GMSPolyline *_polyline;
GMSMarker *_markerStart;
GMSMarker *_markerFinish;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_mapView.settings.myLocationButton = YES;
_mapView.myLocationEnabled = YES;
_mapView.delegate = self;
}
- (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);
}
#pragma mark - GMSMapViewDelegate
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate
{
_polyline.map = nil;
_markerStart.map = nil;
_markerFinish.map = nil;
[_coordinates addObject:[[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude]];
if ([_coordinates count] > 1)
{
[_routeController getPolylineWithLocations:_coordinates travelMode:TravelModeDriving andCompletitionBlock:^(GMSPolyline *polyline, NSError *error) {
if (error)
{
NSLog(#"%#", error);
}
else if (!polyline)
{
NSLog(#"No route");
[_coordinates removeAllObjects];
}
else
{
_markerStart.position = [[_coordinates objectAtIndex:0] coordinate];
_markerStart.map = _mapView;
_markerFinish.position = [[_coordinates lastObject] coordinate];
_markerFinish.map = _mapView;
_polyline = polyline;
_polyline.strokeWidth = 3;
_polyline.strokeColor = [UIColor blueColor];
_polyline.map = _mapView;
}
}];
}
}
#end
getting the location is an asynchronous process. So you need to 'wait' for the location to be updated -- in this case by observing "myLocation"
observe location
this code only works if _mapView is onscreen
// Listen to the myLocation property of GMSMapView.
[_mapView addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
// Ask for My Location data after the map has already been added to the UI.
dispatch_async(dispatch_get_main_queue(), ^{
_mapView.myLocationEnabled = YES;
});
get the location 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];
}
}
I've cannot change the camera's value in the Google Maps API. So that it displays the users position as soon as you open the app, using CoreLocation and passing those values into the camera. I've had a look at some tutorials online, but I haven't managed to solve it yet.
I've tried to make a method that observes when the GPS coordinates have been found and then pass them to the camera. But it still shows 0,0.
#implementation HMSBViewController{
CLLocationManager *_locationManager;
}
#synthesize mapView;
- (NSString *)deviceLocation
{
NSString *theLocation = [NSString stringWithFormat:#"latitude: %f longitude: %f", _locationManager.location.coordinate.latitude, _locationManager.location.coordinate.longitude];
return theLocation;
}
- (void)viewDidLoad
{
mapView.delegate = self;
//[mapView addObserver:self forKeyPath:#"myLocation" options:0 context:nil];
//mapView.settings.myLocationButton = YES;
mapView.myLocationEnabled = YES;
_locationManager = [[CLLocationManager alloc] init];
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation; // Setting the accuracy to the best possible
if([_locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[_locationManager requestAlwaysAuthorization];
}
[_locationManager startUpdatingLocation];
}
- (void)viewWillAppear{
[mapView addObserver:self forKeyPath:#"myLocation" options:0 context:nil];
}
- (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:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude
zoom:1];
mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.view = mapView;
NSLog(#"%f, %f", _locationManager.location.coordinate.latitude, _locationManager.location.coordinate.longitude);
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([keyPath isEqualToString:#"myLocation"]) {
CLLocation *location = [object myLocation];
CLLocationCoordinate2D target = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
[mapView animateToLocation:target];
#try {
[mapView removeObserver:self forKeyPath:#"myLocation"];
} #catch(id exception){
;
}
}
}
Any suggestions would be much appreciated!
You need to set the locationManager delegate and then use the delegate method
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
to retrieve the location. Once you have the location, then call your map function to populate Google
I've been struggling to change the camera's value in the Google Maps API. So that it displays the users position as soon as you open the app, using CoreLocation and passing those values into the camera.
There's some other tutorials online, but nothing that works for me.
If you could help it would be massively appreciated.
#implementation HMSBViewController{
CLLocationManager *_locationManager;
}
- (NSString *)deviceLocation
{
NSString *theLocation = [NSString stringWithFormat:#"latitude: %f longitude: %f", _locationManager.location.coordinate.latitude, _locationManager.location.coordinate.longitude];
return theLocation;
}
- (void)viewDidLoad
{
//mapView.settings.myLocationButton = YES;
mapView.myLocationEnabled = YES;
_locationManager = [[CLLocationManager alloc] init];
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation; // Setting the accuracy to the best possible
if([_locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[_locationManager requestAlwaysAuthorization];
}
[_locationManager startUpdatingLocation];
}
- (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:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude
zoom:6];
mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.view = mapView;
NSLog(#"%f, %f", _locationManager.location.coordinate.latitude, _locationManager.location.coordinate.longitude);
}
When the app runs the coordinates are always set to zero.
Thanks
This happens because Google Maps API only get your current location after it's placed on the controller view. To solve this limitation you should create a notification that tells your controller when the current location is available.
On your viewWillApper add this observer:
[mapView addObserver:self forKeyPath:#"myLocation" options:0 context:nil];
Then add -(void)observeValueForKeyPath:ofObject:change:context: that is called everytime the keyPath value changes. On this method you can now get the current location and animate the map to it so it shows centered in there. At the end of the method you should deregister the observer since if it's not deregistered this method will be called every time the position changes.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([keyPath isEqualToString:#"myLocation"]) {
CLLocation *location = [object myLocation];
CLLocationCoordinate2D target = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
[mapView animateToLocation:target];
#try {
[map removeObserver:self forKeyPath:#"myLocation"];
} #catch(id exception){
//do nothing, obviously it wasn't attached because an exception was thrown
}
}
}
The map can take a while to get the current location, but it's usually fast.