Displaying current location on Google maps - ios

I have an iOS app that uses Google Maps SDK to display a map within my app.
I have managed to get the map displaying but I dont know how to set the camera or the marker to the users current location.
I have hard coded the coordinates just to test is the map working but I am now stuck on how to display current location of the user.
Here is my code to centre the camera to a coordinate
- (void)viewDidLoad
{
[super viewDidLoad];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:47.995602 longitude:-78.902153 zoom:6];
self.mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.mapView.myLocationEnabled = YES;
self.mapView.mapType = kGMSTypeNormal;
self.mapView.accessibilityElementsHidden = NO;
self.mapView.settings.scrollGestures = YES;
self.mapView.settings.zoomGestures = YES;
self.mapView.settings.compassButton = YES;
self.mapView.settings.myLocationButton = YES;
self.mapView.delegate = self;
self.view = self.mapView;
[self placeMarkers];
}
And here is the code to display the marker at coordinates
-(void)placeMarkers
{
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(47.995602, -78.902153);
marker.title = #"PopUp HQ";
marker.snippet = #"Durham, NC";
marker.icon = [GMSMarker markerImageWithColor:[UIColor blueColor]];
marker.opacity = 0.9;
marker.map = self.mapView;
}
I have tried to get the current position as follows:
CLLocationCoordinate2D *myLocation = self.mapView.myLocation.coordinate;
but I get the error:
Initializing 'CLLocationCoordinate2D' with an expression of incompatible type 'CLLocationCoordinate2D'
How can I get the current location to pass to the camera as well as marker?

CLLocationCoordinate2D is just a struct containing a latitude and longitude, so you can simply use
CLLocationCoordinate2D myLocation = self.mapView.myLocation.coordinate;
It is also worth using KVO to observe changes to myLocation, as it is possible that the mapView won't yet have a valid location.
To explain further about KVO:
You can add an observer for the myLocation property as follows:
[self.mapView addObserver:self
forKeyPath:#"myLocation"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
You should then implement the following method:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqualToString:#"myLocation"]) {
// NSLog(#"My position changed");
}
}
You can then safely access self.mapView.myLocation.coordinate knowing that the location is valid.
Don't forget to remove yourself as an observer when the mapview is deallocated:
[self.mapView removeObserver:self forKeyPath:#"myLocation"];
As Saxon has already mentioned, the mapview will show it's own current position indicator. The marker that you are adding will be shown in addition, but it is likely that mapview doesn't yet having a valid position when you are creating the marker, so it is being added at latitude/longitude 0,0 which is in the middle of the ocean.

When you set myLocationEnabled to YES then the map automatically adds a marker at your current location. So you probably don't need to add your own?
It takes time for the device and your app to determine your location. When it starts up it probably doesn't know your location yet, so it defaults to lat/lon of zero, which is off Africa.
As NigelG said, you can use KVO on the myLocation property to find out when the position updates.

Related

Google Maps' Custom Marker icon is not tappable (Using delegate)

I have implemented the Google Maps in my iOS app and to show User Location, I am using custom Marker Icon. Everything is working properly. I have implemented the GMSMapViewDelegate.
The issue is that the event didTapAtCoordinate: is not getting fired when I tap on the Marker Icon, but it does when I tap anywhere on the Map. Just the marker is not tappable while I have tried to set it marker.tappable = YES;
I have searched over the internet but couldn't get that what I am doing wrong or missing.
Below is the code:
/** SETUP MAP & MARKERS **/
-(void) setupMapMarkers {
self.mapView.delegate = self;
/** SET CAMERA POSITION ON MAP **/
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:[self.userObject.latitude doubleValue]
longitude:[self.userObject.longitude doubleValue]
zoom:10];
self.mapView.camera = camera;
/** ADDING USER'S LOCATION MARKER **/
CLLocationCoordinate2D position = CLLocationCoordinate2DMake([self.userObject.latitude doubleValue], [self.userObject.longitude doubleValue]);
GMSMarker *marker = [GMSMarker markerWithPosition:position];
marker.tappable = YES;
NSURL *url = [[NSBundle mainBundle] URLForResource:#"pin_user_active" withExtension:#"gif"];
marker.icon = [UIImage animatedImageWithAnimatedGIFData:[NSData dataWithContentsOfURL:url]];
marker.map = self.mapView;
}
#pragma mark - GMSMapViewDelegate
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
NSLog(#"You tapped at %f,%f", coordinate.latitude, coordinate.longitude);
}
// Added it just to check, if it works on tap
- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay {
NSLog(#"tapped");
}
Give something to marker.title = #"some text" and call this delegate method:
- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker;
When you click on the title, this method will be invoked.
After going through GOOGLE MAPS COCOA DOCS, got to know that there is another delegate method specifically for markers tap.
For delegate method
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate
It states that:
Called after a tap gesture at a particular coordinate, but only if a marker was not tapped. This is called before deselecting any currently selected marker (the implicit action for tapping on the map).
So for markers tap event we need:
- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker
I hope it will help others too.

Google Maps iOS SDK, Getting Current Location of user

For my iOS app (building in iOS7),i need to show user's current location when the app load.I am using Google Maps iOS SDK. I am following this
Google Map
But i can't figure it out. Please help if you go through the path.
Forget my previous answer. It works well if you use the native MapKit.framework.
In fact GoogleMaps for iOS do all the work for you. You don't have to use CoreLocation directly.
The only thing you have to do is to add yourMapView.myLocationEnabled = YES; and the framework will do everything. (Except center the map on you position).
What I have done : I simply followed the steps of the following documentation. And I got a map centered on Sydney but if I zoomed out and moved to my place (if you use a real device, otherwise use simulator tools to center on Apple's location), I could see the blue point on my position.
Now if you want to update the map to follow your position, you can copy Google example MyLocationViewController.m that is included in the framework directory. They just add a observer on the myLocation property to update the camera properties:
#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
With the doc I gave you and the samples included in the framework you should be able to do what you want.
It seems Google Maps iOS SDKcannot access to the device position.
So you have to retrieve the position by using CLLocationManagerof iOS.
First, add the CoreLocation.framework to your project :
Go in Project Navigator
Select your project
Click on the tab Build Phases
Add the CoreLocation.framework in the Link Binary with Libraries
Then all you need to do is to follow the basic exemple of Apple documentation.
Create a CLLocationManager probably in your ViewDidLoad:
if (nil == locationManager)
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
//Configure Accuracy depending on your needs, default is kCLLocationAccuracyBest
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
// Set a movement threshold for new events.
locationManager.distanceFilter = 500; // meters
[locationManager startUpdatingLocation];
With the CLLocationManagerDelegate every time the position is updated, you can update the user position on your Google Maps :
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// If it's a relatively recent event, turn off updates to save power.
CLLocation* location = [locations lastObject];
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 15.0) {
// Update your marker on your map using location.coordinate.latitude
//and location.coordinate.longitude);
}
}
Xcode + Swift + Google Maps iOS
Step by step recipe:
1.) Add key string to Info.plist (open as source code):
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs your location to function properly</string>
2.) Add CLLocationManagerDelegate to your view controller class:
class MapViewController: UIViewController, CLLocationManagerDelegate {
...
}
3.) Add CLLocationManager into your class:
var mLocationManager = CLLocationManager()
var mDidFindMyLocation = false
4.) Ask for permission and add observer:
override func viewDidLoad() {
super.viewDidLoad()
mLocationManager.delegate = self
mLocationManager.requestWhenInUseAuthorization()
yourMapView.addObserver(self, forKeyPath: "myLocation", options: NSKeyValueObservingOptions.new, context: nil)
...
}
5.) Wait for authorization and enable location in Google Maps:
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if (status == CLAuthorizationStatus.authorizedWhenInUse) {
yourMapView.isMyLocationEnabled = true
}
}
6.) Add observable for change of location:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if (!mDidFindMyLocation) {
let myLocation: CLLocation = change![NSKeyValueChangeKey.newKey] as! CLLocation
// do whatever you want here with the location
yourMapView.camera = GMSCameraPosition.camera(withTarget: myLocation.coordinate, zoom: 10.0)
yourMapView.settings.myLocationButton = true
mDidFindMyLocation = true
print("found location!")
}
}
That's it!
On any iOS device, get the user's location with Core Location. Specifically, you want the CLLocation class (and CLLocationManager).
Is delegate method didTapMyLocationButton is not way?
https://developers.google.com/maps/documentation/ios/reference/protocol_g_m_s_map_view_delegate-p#ac0e0171b811e839d9021800ca9fd33f4
- (BOOL)didTapMyLocationButtonForMapView:(GMSMapView *)mapView {
return YES;
}
And you can get location by
(lldb) po mapView.myLocation
<+37.33243033,-122.03088128> +/- 386.93m (speed -1.00 mps / course -1.00) # 5/19/14, 6:22:28 PM Moscow Standard Time
The current location won't show on the simulator... connect a real device and give it a try
I spent 2 days running in the simulator and don't know that it doesn't simulate locations
there are many methods...
I used this method and it works in all cases. Google gives you everything with the reponse in json format and its on you how you deal with that data.
Some steps are there to load google map in your project.
find the api key from this link https://developers.google.com/places/ios-api/
sign in with your google account and add your project and create a ios key.
then use this in your project
enable all the api needed for google map
a-googlemaps sdk for ios
b-googlemap direction api
c-" " javasripts api
d- picker api
e- places api for ios
f distance matrix api
in appdelegate method...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GMSServices provideAPIKey:#"xxxxxxxx4rilCeZeUhPORXWNJVpUoxxxxxxxx"];
return YES;
}
add all needed library and frameworks in your project
if google map is not working it means you have to add required framework
all the best play with google map

Could not get current location using Google Map API (GMSMapView)

I try to get the direction from current location to other point using Google Map API. Everything is OK when i input the origin point and destination point manually. But, when i try to set the origin point as current location, the location is null as the following code:
mainMap=[[GMSMapView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithTarget:[mainMap.myLocation coordinate] zoom:13];
mainMap.camera=camera;
mainMap.myLocationEnabled=YES; // <---- The blue point appear on map: it's exactly my location
[self.view addSubview:mainMap];
//Get mylocation
CLLocation *myLocation = mainMap.myLocation; // <----- NULL
Is there any body know what is my problem here? Tks a lot
The thing is: Getting a location is asynchronous and how you do it is expect it to block till its there... which is not how it works
you have to add a KVO observer inn the map and observer myLocation.
Then when your observe method gets called, you get the myLocation.
(that's how the blue dot works too :))
- (void)viewDidLoad {
//...
[self.mapView addObserver:self forKeyPath:"myLocation" options:0 context:nil];
}
- (void)dealloc {
[_mapView removeObserver:self forKeyPath:#"myLocation"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([keyPath isEqualToString:#"myLocation"]) {
CLLocation *l = [object myLocation];
//...
}
}

GMSMapView myLocation not giving actual location

I have a GMSMapView properly loaded and working inside my viewcontroller
what i'm not being able to do is setting the GMSCameraPosition around my location
this is my code:
mapView_.myLocationEnabled = YES;
CLLocation* myLoc = [mapView_ myLocation];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:myLoc.coordinate.latitude
longitude:myLoc.coordinate.longitude
zoom:4];
[mapView_ setCamera:camera];
GPS is enabled and application has all needed permissions but myLocation returns a nil CLLocation, consequentially cameraWithLatitude:longitude:zoom: get 0 0 coordinates and displays Africa instead of my actual location (that is not in africa :) )
From official Google Maps iOS SDK documentation:
(BOOL) myLocationEnabled [read, write, assign]
Controls whether the My Location dot and accuracy circle is enabled.
Defaults to NO.
(CLLocation*) myLocation [read, assign]
If My Location is enabled, reveals where the user location dot is being drawn.
If it is disabled, or it is enabled but no location data is available, this will be nil. This property is observable using KVO.
So when you set mapView_.myLocationEnabled = YES;, it only tells the mapView to reveal the blue dot only if you have a location value given to the myLocation property. The sample code from Google shows how to observe the user location using the KVO method.(Recommended) You can also implement the CLLocationManagerDelegate method, to update the mapView.
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[mapView animateToLocation:newLocation.coordinate];
// some code...
}
Here are the code from google maps sample code on how to use KVO to update user location.
// in viewDidLoad method...
// 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;
});
- (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];
}
}
Try to using MapKit, under the VieDidLoad or ViewWillApper using:
myMapView.showsUserLocation = YES;
You can add this simple code under the IBAction if you want, like a :
- (IBAction)getLocation:(id)sender{
myMapView.showsUserLocation = YES;
}
I hope this help you

MKMapView cannot scroll and zoom in iOS 5.0

I run this code normally in iOS 4.3. But when I change the project to iOS 5.0, I cannot scroll and zoom the map.
Can anybody tell me why has this problem? How can I solve it?
The code is:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect rect = CGRectMake(0, 0, 320, 460);
map = [[MKMapView alloc] initWithFrame:rect];
map.showsUserLocation = YES;
MKUserLocation *userLocation = map.userLocation;
[userLocation addObserver:self forKeyPath:#"location"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
context:nil];
map.scrollEnabled = YES;
map.zoomEnabled = YES;
map.mapType = MKMapTypeStandard;
[self.view addSubview:map];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([change objectForKey:NSKeyValueChangeNewKey] != [NSNull null]) {
MKCoordinateRegion region;
CLLocationCoordinate2D testCoordinate;
double lat = 22.195579570451734;
double lng = 113.542275265336;
testCoordinate.latitude = lat;
testCoordinate.longitude = lng;
region.center = testCoordinate;
MKCoordinateSpan span;
span.latitudeDelta = 0.0011;
span.longitudeDelta = 0.0011;
region.span = span;
[map setRegion:region animated:YES];
}
}
The code is observing changes to the user location and updating the map's region to some fixed region when that happens.
In the iOS Simulator before iOS 5.0, the user location changes were not simulated and so the location change observer method would either not fire or not fire as frequently. So if you scrolled or zoomed the map, the map would stay that way until the observer method fired (probably never).
In the iOS Simulator for iOS 5.0, the user location changes are (or can be) simulated. Under the iOS Simulator's Debug menu, there is a Location sub-menu. If this is set to anything but None, the user location change event will happen and cause the observer method to fire. If the Location setting is City Bicycle Ride, City Run, or Freeway Drive, the user location will change very frequently.
Since your observer method is re-setting the map's region to some fixed area every time the user location changes, any scrolling or zooming you do to the map is almost immediately un-done.
Change the Location setting to either None or Custom Location (which will fire only once).
An un-related point is you don't need to use KVO to observe changes to the user location. Unless your app needs to run on iOS 3.0 or earlier, you should use the MKMapViewDelegate method mapView:didUpdateUserLocation: instead.

Resources