Im just getting into MapViews on iOS, and want to show a car continuously moving as a blue dot. Would this be considered a map annotation?
Yes. As an example check out the in Simulator Debug > Location > City Bike Ride . It does a slow loop round San Francisco(?)
To listen to updates implement in your Mapview delegate
- (void)mapView:(MKMapView *)amapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(#"im here! - %f,%f",userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude);
}
and to adjust the annotation implement
- (MKAnnotationView *) mapView:(MKMapView *)amapView viewForAnnotation:(id <MKAnnotation>) annotation{
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
NSLog(#"annotation = %#",((NSObject *)annotation));
MKAnnotationView *annView;
annView = [amapView dequeueReusableAnnotationViewWithIdentifier:#"currentloc"];
if(!annView)
{
annView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"currentloc"] autorelease];
((MKPinAnnotationView *)annView).pinColor = MKPinAnnotationColorGreen;
((MKPinAnnotationView *)annView).animatesDrop=TRUE;
annView.canShowCallout = YES;
annView.calloutOffset = CGPointMake(-5, 5);
annView.draggable = YES;
}
return annView;
}
The snip I have put in just goes with the default blue dot with accuracy circle by returning nil for MKUserLocation but your implementation may be different.
Related
I have added a custom annotation and a percentage label on it.
By pressing the button in red circle, I want to change value of label from percentage to business name.
My Code:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[BusinessCustomAnnotation class]]) {
MKAnnotationView *annotationView = (MKAnnotationView *) [mapViewOffers dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
UILabel* category = [[UILabel alloc] initWithFrame:CGRectMake(annotationView.frame.size.width / 2, 15, 55, 20)];
BusinessCustomAnnotation *myAnnotationView = (BusinessCustomAnnotation *)annotation;
NSLog(#"Type One Offer! = %i", mapTypes);
[category setAdjustsFontSizeToFitWidth:YES];
if (mapTypes == 1) {
category.text = [NSString stringWithFormat:#"%#%#", myAnnotationView.offerPercentage, #"%"];
}else if (mapTypes == 2){
category.text = myAnnotationView.businessName;
}else if (mapTypes == 3){
category.text = myAnnotationView.businessName;
}
[category setMinimumScaleFactor:1.0];
category.font = [UIFont systemFontOfSize:15.0 weight:5.0];
category.textAlignment = NSTextAlignmentCenter;
[annotationView addSubview:category];
annotationView.enabled = YES;
annotationView.canShowCallout = NO;
annotationView.image = [UIImage imageNamed:#"iconMapMarker"];//here we use a nice image instead of the default pins
} else {
annotationView.annotation = annotation;
}
return annotationView; }return nil; }
Above mapview delegate is calling for one time only.
Waiting for the solution.
Thanks in advance for helping me.
There are two ways of detecting user interaction with your annotation view. The common technique is to define a callout (that standard little popover bubble that you see when you tap on a pin in a typical maps app) for your MKAnnotationView. And you create the annotation view for your annotation in the standard viewForAnnotation method:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"loc"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
By doing this, you get a callout, but you're adding an right accessory, which is, in my example above, a disclosure indicator. That way, they tap on your annotation view (in my example above, a pin on the map), they see the callout, and when they tap on that callout's right accessory (the little disclosure indicator in this example), your calloutAccessoryControlTapped is called.
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
//first check your view class here
// here your code for change text on view
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
//first check your view class here
// here your code for change text on view
}
You need to refresh the annotations. In Action of button try this :
mapTypes = 2
for (id<MKAnnotation> annotation in mapView.annotations)
{
[mapView removeAnnotation:annotation];
[mapView addAnnotation:annotation];
}
You can't make any changes to already added annotation pin.To make any changes to the annotation pin you need to remove all the pin and add it back.
Annotations don't refresh.
You have to remove all existing annotations with
[self.mapView removeAnnotations:self.mapView.annotations];
and update your "mapTypes" variable value to "2" or "3" in order to show business name.
Then you can can add your annotations again with [MKMapView addAnnotation:].
The following code below is show custom pin (picture as pin). it can use normally.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
PVAttractionAnnotationView *annotationView = [[PVAttractionAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"Attraction"];
annotationView.canShowCallout = YES;
return annotationView;
}
Then use following code to show current location
[self.mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading];
XCODE jump to main.m and show
Thread 1:Signal SIGABRT
On the other hand if i use the following code
[self.mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading];
and unused all of the following code
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
PVAttractionAnnotationView *annotationView = [[PVAttractionAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"Attraction"];
annotationView.canShowCallout = YES;
return annotationView;
}
Application will show current location normally but it's not show custom pin. It's show the red pin that is the default of system cause i've unused that code.
How can i make custom pin and use FollowWithHeading mode together?
..I'm sorry I do not use English well.
You need a slight change to your viewForAnnotation that examines the class of the annotation and returns the appropriate view. By returning nil the system will use the default view. You also need some additional code to implement view re-use correctly -
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *annotationView=nil;
if ([annotation isKindOfClass:[PVAttractionAnnotation class]]) // Note - put your custom annotation class here
{
annotationView =(MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"Attraction"];
if (annotationView == nil)
{
annotationView = [[PVAttractionAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"Attraction"];
annotationView.canShowCallout = YES;
}
else
{
annotationView.annotation=annotation;
}
}
return annotationView;
}
I'm using the Apple maps. At the moment I have to click on one of my Annotation Pins and the Annotation View is opening, than I can click on this view and something happens. But i want to click on my Annotation Pins and the Map should be zoom in WITHOUT opening the Annotation View first. I tried this, but it doesn't work:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if(someValues > 1){
//If someValues are bigger than one then only zoom in without returning the annotation View
MKCoordinateRegion region = mapView.region;
MKCoordinateSpan span;
span.latitudeDelta = region.span.latitudeDelta/5;
span.longitudeDelta = region.span.longitudeDelta/5;
region.span = span;
region.center = anntotation.coordinate;
[mapView setRegion:region animated:TRUE];
//return 0 returns a default view i know....whats correct?
return 0;
} else {
MKPinAnnotationView *view = nil;
if (annotation != mapView.userLocation)
{
view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"identifier"];
if (nil == view) {
view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"identifier"];
}
[view setPinColor:MKPinAnnotationColorRed];
view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[view setCanShowCallout:YES];
[view setAnimatesDrop:NO];
}
return view;
}
}
Is there any delegate Method i´m missing?
please see the didSelectAnnotationView delegate method to your mapview.
example :
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
if([[view annotation] isKindOfClass:[myMarker class]]) return;
}
And here :
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if([[view annotation] isKindOfClass:[myMarker class]]) return nil;
}
I'm trying to perform a segue when a map annotation pin is tapped. Im using a custom annotation class if that makes a difference.
I've tried
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
NSLog(#"annotation selected");
[self performSegueWithIdentifier:#"mySegue" sender:self];
}
but my NSLog isnt running so I assume the method isnt getting called.
The only other things I've done are add the annotation pin to my map view and set my view controller as the map view delegate.
Here is how I added the annotation to the mapview
SPMapAnnotation *pin = [[SPMapAnnotation alloc] init];
pin.coordinate = spotLocation.coordinate;
pin.title = [spot objectForKey:#"spotName"];
[self.mapView addAnnotation:pin];
How can I make this work? That didSelectAnnotation method seems like it would make this easy to do but I'm not sure how it works.
Apparently I forgot I didnt allocate my mapView until viewDidAppear. Just needed to add
self.mapView.delegate = self;
after I alloc and inited it.
Implement following delegate method
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *annotationView = nil;
if ([annotation isKindOfClass:[SPMapAnnotation class]])
{
annotationView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:#"Pin"];
if (annotationView == nil)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"Pin"];
annotationView.canShowCallout = YES;
annotationView.animatesDrop = YES;
}
}
return annotationView;
}
as didSelectAnnotationView will not be called for standard annotation pin, you need to return MKAnnotationView for didSelectAnnotationView to be called.
In map view, i'm showing current user location. On click on the pin its showing "Current Location". I want to change it to "My Current Location". How can I change it.
Also I want to change the current user location pin color in a timer. Some thing like every one second it should change its color between green, purple and red. Possible to do it?
I'm using map kit's show default location and then manipulating the annotation pin color as below:
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *AnnotationViewID = #"annotationViewID";
SolarAnnotationView* annotationView = (SolarAnnotationView*)[map dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if(annotationView == nil)
{
if([self CLLocationCoordinate2DEquals:mapView.userLocation.location.coordinate withSecondCoordinate:[annotation coordinate]]) //Show current location with green pin
{
annotationView = [[SolarAnnotationView alloc] initWithAnnotation:annotation];
annotationView.delegate = self;
[annotationView setPinColor:MKPinAnnotationColorGreen];
}
else
{
annotationView = [[SolarAnnotationView alloc] initWithAnnotation:annotation];
annotationView.delegate = self;
}
}
return annotationView;
}
- (BOOL) CLLocationCoordinate2DEquals:(const CLLocationCoordinate2D)lhs withSecondCoordinate:(const CLLocationCoordinate2D) rhs{
const CLLocationDegrees DELTA = 0.001;
return fabs(lhs.latitude - rhs.latitude) <= DELTA && fabs(lhs.longitude - rhs.longitude) <= DELTA;
}
If you let the map view show the default annotation view for the user location (blue dot), this is simpler to implement (and you get a nice blue dot with cool animated zooming circle).
If you must show the user location using a pin image instead of a blue dot, then some more work is needed.
First, the simple way using the blue dot:
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
((MKUserLocation *)annotation).title = #"My Current Location";
return nil; //return nil to use default blue dot view
}
//Your existing code for viewForAnnotation here (with some corrections)...
static NSString *AnnotationViewID = #"annotationViewID";
SolarAnnotationView* annotationView = (SolarAnnotationView*)[map dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if(annotationView == nil)
{
{
annotationView = [[[SolarAnnotationView alloc] initWithAnnotation:annotation] autorelease];
//added autorelease above to avoid memory leak
annotationView.delegate = self;
}
}
//update annotation in view in case we are re-using a view
annotationView.annotation = annotation;
return annotationView;
}
If you want to use your custom annotation view for the user location instead, you should put the pin color changing code in the custom view. One way to periodically change the color is using performSelector:withObject:afterDelay:. In the SolarAnnotationView.m, add these two methods:
-(void)startChangingPinColor
{
switch (self.pinColor) {
case MKPinAnnotationColorRed:
self.pinColor = MKPinAnnotationColorGreen;
break;
case MKPinAnnotationColorGreen:
self.pinColor = MKPinAnnotationColorPurple;
break;
default:
self.pinColor = MKPinAnnotationColorRed;
break;
}
[self performSelector:#selector(startChangingPinColor) withObject:nil afterDelay:1.0];
}
-(void)stopChangingPinColor
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
Also add the method headers to the SolarAnnotationView.h file.
Then change the viewForAnnotation method like this:
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *AnnotationViewID = #"annotationViewID";
SolarAnnotationView* annotationView = (SolarAnnotationView*)[map dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if(annotationView == nil)
{
{
annotationView = [[[SolarAnnotationView alloc] initWithAnnotation:annotation] autorelease];
annotationView.delegate = self;
}
}
//Update annotation in view in case we are re-using a view...
annotationView.annotation = annotation;
//Stop pin color changing in case we are re-using a view that has it on
//and this annotation is not user location...
[annotationView stopChangingPinColor];
if([self CLLocationCoordinate2DEquals:mapView.userLocation.location.coordinate withSecondCoordinate:[annotation coordinate]]) //Show current location with green pin
{
[annotationView setPinColor:MKPinAnnotationColorGreen];
annotationView.canShowCallout = YES;
((MKPointAnnotation *)annotation).title = #"My Current Location";
[annotationView startChangingPinColor];
}
return annotationView;
}