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.
Related
I am building an iOS application using google maps SDK. I can add some markers on the maps when user does a longPressAtCoordinate. My problem is that when I am trying to drag a marker the diiLongPressAtCoordinate is fired before the didBeginDraggingMarker so a new marker is added also.
-(void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker{
NSLog(#"begin dragging marker");
}
- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate (CLLocationCoordinate2D)coordinate{
NSLog(#"did long press at mapview");
//when user didLongPressAtCoordinate I add a new marker on the map.
// I want to prevent the execution of this code before the didBeginDraggingMarker method
}
I solved this problem by creating a boolean property called isDragging and changing it's value depending whether a marker is being dragged.
- (void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker
{
self.isDragging = YES;
}
- (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker
{
self.isDragging = NO;
}
Then I validate if a marker is being dragged whenever a long press is detected:
- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate
{
if (self.isDragging) {
return;
}
NSLog(#"Long press detected");
}
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.
I am using am mapview and sometimes my map will zoom onto my users location when I open it but sometimes it will zoom to the middle of an ocean. I don't know what is causing this, this is the code I am using for zooming. I don't want the map to track the user but just zoom to their location once they open the map
-(void) viewDidAppear:(BOOL)animated{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 600.0f, 600.0f);
[self.mapView setRegion:region animated:YES];
}
-(void) viewDidLoad{
[super viewDidLoad];
self.mapView.delegate = self;
[self.mapView setShowsUserLocation:YES];
}
I encountered this issue before. It seems that mapView is slow to load and detect user location sometimes, resulting in your code in viewDidAppear being executed before the map view can check user's location. Thus, the spot in the ocean.
It will be better to use mapView's delegate to display user location when it's ready:
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if(isShowUserLocation)
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 600.0, 600.0);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
isShowUserLocation = NO;
}
}
Set isShowUserLocation = YES in viewDidLoad. This ensures the user location is shown once on entry and also selectively when you need it.
Edit 1:
#implementation MapViewController
{
BOOL isShowUserLocation;
}
-(void) viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
[self.mapView setShowsUserLocation:YES];
isShowUserLocation = YES;
}
Edit 2:
Alternatively, use CLLocationManager - see this post. It allows you stop the updating. Do include CoreLocation.framework. You may need to handle some nitty-gritty issues when interacting CLLocationManager with MapView though.
When you pass 0's for lat and long, you will git a spot in the middle of the ocean south of Ghana in Africa.
Using latitude and longitude I want to display the correct position by annotation. My app is showing the area, but not the correct position by annotation.
Here is my code:
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mapView.delegate=self;
[self.mapView setShowsUserLocation:YES];
locatinmanager=[[CLLocationManager alloc]init];
[locatinmanager setDelegate:self];
[locatinmanager setDistanceFilter:kCLDistanceFilterNone];
[locatinmanager setDesiredAccuracy:kCLLocationAccuracyBest];
}
#pragma mark - MKMapViewDelegate methods.
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
MKCoordinateRegion region;
region.center.latitude=13.0839;
region.center.longitude=80.2700;
[mapView setRegion:region animated:YES];
}
You have set the region for your map but not the annotation.
For blue dot you need to add annotation for the same latitude and logitude.
Add following code with yours.
MapPoint *mp = [[MapPoint alloc] initWithCoordinate:**YouReagionsCordinat** title:#"**yourLocation**"];
[mapView addAnnotation:mp];
If still you are stucking then go through This tutorial
.
Is there a easy way to hide it? I use the user location, but I don't want to show the blue dot. How can I hide it?
-- edit--
Am I using something wrong?
#interface ALMapaViewController : UIViewController <MKMapViewDelegate,
MKAnnotation>
{
IBOutlet MKMapView *mapaPrincipal;
id<ALMapaViewControllerDelegate> delegateMap;
CLLocationCoordinate2D coordinate;
}
my .m
#implementation ALMapaViewController
- (void)viewDidLoad{
[super viewDidLoad];
[mapaPrincipal setMapType:MKMapTypeStandard];
[mapaPrincipal setZoomEnabled:YES];
[mapaPrincipal setScrollEnabled:YES];
[mapaPrincipal.userLocation addObserver:self
forKeyPath:#"location"
options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)
context:nil];
[mapaPrincipal setShowsUserLocation:YES];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
MKCoordinateRegion region;
region.center = mapaPrincipal.userLocation.coordinate;
MKCoordinateSpan span;
span.latitudeDelta = 0.005f;
span.longitudeDelta = 0.005f;
region.span = span;
[mapaPrincipal setRegion:region animated:YES];
self.coordinate = region.center;
[mapaPrincipal addAnnotation:self];
[mapaPrincipal setShowsUserLocation:NO];
}
#end
I already used the showUserLocation and it still show the blue dots.
You want to receive user location updates but not show the blue dot.
One option is to use CLLocationManager to get updates instead of the map view's showsUserLocation. Call startUpdatingLocation on the location manager and implement its locationManager:didUpdateToLocation:fromLocation: delegate method.
If you don't want to use CLLocationManager, another option is to hide the user location view that is created by the map view by setting it's hidden property to YES in the map view's didAddAnnotationViews delegate method. The map view will continue to receive user location updates (because you are not setting showsUserLocation to NO) but the blue dot won't show because you're hiding its view.
An example of the second option is shown in this answer:
Hide MKUserLocation when MKMapView showsUserLocation == YES
An unrelated point is that you don't need to use key-value-observing to monitor changes to the map view's userLocation property. Use the mapView:didUpdateUserLocation: delegate method instead.
Very simple buddy
[mapView setShowUserLocation:NO];
You can hide the user location's view in the didAddAnnotationViews delegate method:
(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView *ulv = [mapView viewForAnnotation:mapView.userLocation];
ulv.hidden = YES;
}
check this https://stackoverflow.com/a/9713085/1344237
You can use this method
[mapViewSelf setShowsUserLocation:NO];
this works fine.
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews (NSArray<MKAnnotationView *> *)views {
MKAnnotationView *ulv = [mapView viewForAnnotation:mapView.userLocation];
if (ulv) {
CALayer *layer = [ulv valueForKeyPath:#"_accuracyLayer"];
if (layer) {
[layer removeFromSuperlayer];
}
}
}
The marked answer is correct, hiding it is very effective. Here's the delegate implemented code the accepted answer was referring to:
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
if let userView = views.first(where: { $0.annotation is MKUserLocation }) {
userView.isHidden = true
}
}