Adding Disclosure Indicator to map pins iOS 5 - ios

I can't seem to be able to add a disclosure button to my map annotations.
I implemented the MKMapViewDelegate to my view controller as well. What am I missing?
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *mapPin = nil;
if(annotation != map.userLocation)
{
static NSString *defaultPinID = #"defaultPin";
mapPin = (MKPinAnnotationView *)[map dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if (mapPin == nil )
mapPin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
mapPin.canShowCallout = YES;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mapPin.rightCalloutAccessoryView = infoButton;
}
return mapPin;
}

That code should work but check the following:
Is the map view's delegate property set? Declaring that the view controller implements the MKMapViewDelegate protocol does not actually tell the map view which object is implementing the delegate methods. In code, do map.delegate = self; or in IB connect the delegate outlet to File's Owner.
Is the annotation's title property set to non-blank? If the title is blank, no callout will show.
Also, unrelated but, when the dequeue returns an annotation view, you should update its annotation property to the current annotation (it might have been used for another annotation previously). Additionally, unless you're using ARC, you should also autorelease the view.
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *mapPin = nil;
if(annotation != map.userLocation)
{
static NSString *defaultPinID = #"defaultPin";
mapPin = (MKPinAnnotationView *)[map dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if (mapPin == nil )
{
mapPin = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:defaultPinID] autorelease];
mapPin.canShowCallout = YES;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mapPin.rightCalloutAccessoryView = infoButton;
}
else
mapPin.annotation = annotation;
}
return mapPin;
}

Related

How to change UILabel value in CustomAnnotation by clicking button in iOS

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:].

MKAnnotationView not displayed when object creation is performed within a custom annotation class

Environment
Xcode: 5.0.2, Device: iPhone,
iOS: iOS 7
I am trying to use the mapView:viewForAnnotation: delegate method. Within this method, if I create the MKAnnotationView object, the pin gets displayed without any issue. Here is the working code:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[CustomeAnnotation class]])
{
// CustomeAnnotation *myLocation = (CustomeAnnotation *)annotation;
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"MyCustomAnnotation"];
if (annotationView == nil)
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"MyCustomAnnotation"];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
//annotationView.image = [UIImage imageNamed:#"park_icon"];
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
// annotationView = myLocation.createAnnotationView;
else
annotationView.annotation = annotation;
//return nil;
return annotationView;
}
else
return nil;
}
When I create a class method and move the MKAnnotationView object creation and property setting within the class method and I call it from the mapView:viewForAnnotation: delegate method, the pin does not appear.
Here is the code for the two methods in question (mapView:viewForAnnotation: and createAnnotationView):
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mapView.delegate = self;
CLLocationCoordinate2D baysideParkCoordinates = CLLocationCoordinate2DMake(25.774407, -80.185797);
CustomeAnnotation *baysideParkAnnotation = [[CustomeAnnotation alloc] initWithTitle:#" Bayfront Park"
coordinate:baysideParkCoordinates];
[self.mapView addAnnotation:baysideParkAnnotation];
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[CustomeAnnotation class]])
{
CustomeAnnotation *myLocation = (CustomeAnnotation *)annotation;
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"MyCustomAnnotation"];
if (annotationView == nil)
annotationView = [myLocation createAnnotationView];
else
annotationView.annotation = annotation;
// return nil;
return annotationView;
}
else
return nil;
}
#end
The custom class
#import "CustomeAnnotation.h"
#implementation CustomeAnnotation
-(id)initWithTitle:(NSString *)newTitle coordinate:(CLLocationCoordinate2D) newCoordinate
{
self = [super init];
if (self)
{
self.title = newTitle;
self.coordinate = newCoordinate;
}
return self;
}
-(MKAnnotationView *)createAnnotationView
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:self reuseIdentifier:#"MyCustomAnnotation"];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
//annotationView.image = [UIImage imageNamed:#"park_icon"];
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
#end
The import statement for the CustomeAnnotation class is included in the ViewController.h file.
At this point I believe I am not passing back correctly the MKAnnotationView object back to the method call in the ViewController implementation file. Could anyone tell me what is it that I am doing wrong on the second set of code?
In the second set of code, in createAnnotationView, the annotation is not showing because it's not setting the image.
Note that an MKAnnotationView does not have a default image so if you don't set it, the annotation is invisible.
Uncomment the setting of the image (or create an MKPinAnnotationView instead).
The reason the first set of code works (even though it is also creating an MKAnnotationView) is because there's actually a small bug in the code:
MKAnnotationView *annotationView = [mapView dequeue...
if (annotationView == nil)
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] init...
//^^^^^^^^^^^^^^^^ Here, the code declares a NEW, LOCAL variable
// named annotationView but it has no connection to the
// annotationView declared outside the if-block.
Because the annotationView declared outside the if is never set, it stays nil and that's what the delegate method actually returns.
When you return nil from viewForAnnotation, the map view creates a default view for you (a red pin for your annotations, a blue dot for the user location).
To fix the first set of code, don't declare a new, local variable. Just set the variable:
MKAnnotationView *annotationView = [mapView dequeue...
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] init...
and don't forget to set the image (or create an MKPinAnnotationView instead).

standard map annotation for iOS

I want to display my custom annotations in the map and my current location as the standard pin in the map view with the blue color.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MapPin";
if ([annotation isKindOfClass:[MyAnnotations class]]) {
MyAnnotations *ann= annotation;
MKAnnotationView *annotationView = (MKAnnotationView *) [self.map dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
if (ann.custom){
annotationView.image = [UIImage imageNamed:#"custom.png"];
}else{
//?? annotationView.image = [UIImage imageNamed:#"bluePin.png?"];
}
} else {
annotationView.annotation = annotation;
}
if(ann.custom){
UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[nextButton addTarget:self action:#selector(annotationPicked) forControlEvents:UIControlEventTouchUpInside];
annotationView.rightCalloutAccessoryView=nextButton;
}
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.multipleTouchEnabled = NO;
return annotationView;
}
return nil;
}
If the custom property is to distinguish between your annotations and the map view's user location, that case is already handled by the first if which checks the annotation's class and the custom property would be unnecessary.
The map view's user location annotation is of type MKUserLocation so the code will return nil in that case and the map view will show the standard blue dot (assuming showsUserLocation is YES).
However, if the custom property is to distinguish between two types of your own annotations, then one problem is that it doesn't handled re-used annotation views properly (when annotationView != nil).
When an annotation view is re-used, its image and rightCalloutAccessoryView may not be right for the current annotation so those properties need to be set (or cleared) whether a view is being re-used or not. For example:
if ([annotation isKindOfClass:[MyAnnotations class]]) {
MyAnnotations *ann= annotation;
MKAnnotationView *annotationView = (MKAnnotationView *) [self.map dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.multipleTouchEnabled = NO;
} else {
annotationView.annotation = annotation;
}
//set view properties that depend on annotation-specific properties
//regardless of whether view is new or re-used...
if (ann.custom)
{
annotationView.image = [UIImage imageNamed:#"custom.png"];
UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[nextButton addTarget:self action:#selector(annotationPicked) forControlEvents:UIControlEventTouchUpInside];
annotationView.rightCalloutAccessoryView=nextButton;
}
else
{
annotationView.image = [UIImage imageNamed:#"bluePin.png"];
annotationView.rightCalloutAccessoryView = nil;
}
return annotationView;
}
Though if the custom property is just to separate all your annotations from the map view's user location, it's unnecessary in the first place (as long as you check the annotation's class and set showsUserLocation to YES).
may be you put custom code in this event .because when you click on current location annotation this method calls and may be bacause of that code application crashes.
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
}
Thanks.

setting the MKMapViewDelegate makes my marker disappear in iOS

I am using MapKit and I am having the exact problem.
This is my code:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyLocation class]]) {
MKAnnotationView *annotationView = (MKAnnotationView *) [mymap_ios dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
} else {
annotationView.annotation = annotation;
}
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
return nil;
}
In this code, I can see the pin but not the blue button next to it so as. It seems that I have forgotten to do this:
mymap_ios.delegate=self;
But when I add this, the marker is not shown at all.
Can you help me on that?
When you don't set the map view's delegate, it doesn't call your viewForAnnotation and creates a default red pin without any accessory buttons.
When you set the delegate, it is calling your viewForAnnotation method but you are creating a plain MKAnnotationView which by default does not have any pre-set image or view (it's blank).
Either set the annotation view's image, add some content to the view, or simply create an MKPinAnnotationView instead of an MKAnnotationView:
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [mymap_ios ...
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] init...
Also make sure that the annotation objects you add are of type MyLocation otherwise they will appear as plain red pins without an accessory button.

UserLocation Image doesn't move

I dont understand why the userLocation doesnt move when i set a costum image on it.
If i don't set an image, it uses the default pin blue and it works; i can see the userlocation moves when the postion changes.
here is my viewForAnnotation taken from an other post.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString* AnnotationIdentifier = #"Annotation";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mk dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView)
{
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.animatesDrop = NO;
pinView.canShowCallout = YES;
}
else
{
pinView.annotation = annotation;
}
if (annotation == mk.userLocation)
pinView.image = [UIImage imageNamed:#"PositionPin.png"];
else
pinView.image = [UIImage imageNamed:#"PositionPin.png"];
return pinView;
}
This appears to be a bug in the map view (still present in iOS 6) where the user location coordinates no longer update when a custom annotation view is used (even though documentation suggests it will work).
A workaround is to use Core Location to get user location updates and create your own annotation (instead of using the map view's userLocation) and then supplying a custom image for it in viewForAnnotation.
See the answer to Custom Annotation view for userlocation not moving the mapview for more details and some sample code to implement the workaround.
In addition, note that when using a custom image for your annotation view, you should use MKAnnotationView instead of MKPinAnnotationView.
When using MKPinAnnotationView, it sometimes shows its default pin image instead of your custom image.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString* AnnotationIdentifier = #"Annotation";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mk dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView)
{
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.animatesDrop = NO;
pinView.canShowCallout = YES;
}
pinView.annotation = annotation;
pinView.image = [UIImage imageNamed:#"PositionPin.png"];
return pinView;
}

Resources