Change ONLY the bubble of information with a MKPinAnnotationView? - ios

I want to use a normal MKPinAnnotationView, but I want to use a custom view for the callout. Every solution I can find seems to be a hack or doesn't maintain the normal dropped pin behavior
Can anyone provide an example of the simplest way to replace the callout of an MKPinAnnotationView?

You have to override the
-(MKAnnotationView*) mapView:(MKMapView *)mkMapView viewForAnnotation:(id<MKAnnotation>)annotation
function, to return a custom MKAnnotationView. In this view (that you create), you can customise the layout using the drawRect function.
This is what my custom bubble looks like:
And this is my viewForAnnotation:
-(MKAnnotationView*) mapView:(MKMapView *)mkMapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[YourAnnotation class]]) {
YourAnnotationView *yourAnnotationView = (YourAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"YourAnnotation"];
if(!yourAnnotationView)
{
yourAnnotationView = [[YourAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:#"YourAnnotation"];
}
[yourAnnotationView setTitle:annotation.title];
[yourAnnotationView setSubtitle:annotation.subtitle];
yourAnnotationView.draggable = YES;
return yourAnnotationView;
}
else
{
MKPinAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"GPXAnnotation"];
annotationView.canShowCallout = NO;
annotationView.pinColor = MKPinAnnotationColorGreen;
annotationView.draggable = YES;
return annotationView;
}
return nil;
}
Hope it can help you in the right direction!

Related

Custom Callout on MKAnnotationView

I wish to show a completely custom callout view on top of the MKAnnotationView when tapped. I have stumbled through a few answers but none of them have worked and I have seen it in a few apps so I know it can be done. I would also like to show a few buttons on the callout and perform different actions upon tapping on them. I am working on Objective-C and would really appreciate any help.
You need to put your custom code on viewForAnnotation method and update view as per your requirement:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
return nil;
}
else if ([annotation isKindOfClass:[YOUR_CUSOM_ANNO_CLASS_NAME class]]) // use whatever annotation class you used when creating the annotation
{
static NSString * const identifier = #"customAnno";
MKAnnotationView* annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView)
{
annotationView.annotation = annotation;
}
else
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:identifier];
}
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:];
return annotationView;
}
return nil;
}
There is a wonderful demo by sghiassy on github. It will help you more to understand Annotation.
Starting with iOS 9 you can use the detailCalloutAccessoryView property on MKAnnotationView. You can set this to any view. You have a Ray Wenderlich tutorial for this on Chapter 14 of iOS 9 by Tutorials.

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

Dragging the map after dragging my MKAnnotationView does not move the MKAnnotationView with it

MKPinAnnotationView does not allow you to use a custom image as 'pin' and enable dragging at the same time, because the image will change back to the default pin as soon as you start dragging. Therefore I use an MKAnnotationView instead of an MKPinAnnotationView.
While using MKAnnotationView instead of MKPinAnnotationView does keep your custom image shown as your 'pin' it doesn't support the drag & drop animation that you get with the default pin.
Anyway, my issue is that after I drag my custom MKAnnotationView to a new point on the map and then move the map itself the MKAnnotationView does not move with the map anymore.
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
static NSString *defaultID = #"myLocation";
if([self.annotation isKindOfClass:[PinAnnotation class]])
{
//Try to get an unused annotation, similar to uitableviewcells
MKAnnotationView *annotationView = [self.mapView dequeueReusableAnnotationViewWithIdentifier:defaultID];
//If one isn't available, create a new one
if(!annotationView)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:self.annotation reuseIdentifier:defaultID];
annotationView.canShowCallout = YES;
annotationView.draggable = YES;
annotationView.enabled = YES;
}
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 32, 32)];
imgView.image = self.passableTag.image;
annotationView.leftCalloutAccessoryView = imgView;
annotationView.image = [UIImage imageNamed:[Constants tagIconImageNameForTagType:self.passableTag.type]];
return annotationView;
}
return nil;
}
Just set the annotationView.dragState to MKAnnotationViewDragStateNone after ending the drag:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState {
if ([view.annotation isKindOfClass:[PinAnnotation class]]) {
if (newState == MKAnnotationViewDragStateEnding) {
view.dragState = MKAnnotationViewDragStateNone;
}
}
}
I had the same problem and I solved it adding "setDragState" to my MKAnnotationView class.
This is an old solution but it worked to me (iOS8).
Don't reuse MKAnnotationView and it will work.

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.

MapKit annotation custom image doesn't work

I have a problem with the custom image on MapKit annotation. Building a sample project where I am performing the same test, it works properly (although the drop effect and the custom image do not work).
But when I use exactly the same function on my map view project, the custom image does not appear. I noticed that the color pin change function MKPinAnnotationColorPurple does not work either. Is it possible that it depends on some project properties?
The code is:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyLocation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.animatesDrop= NO;
annotationView.image=[UIImage imageNamed:#"arrest.png" ];//here we use a nice image instead of the default pins
annotationView.canShowCallout = YES;
UIButton *btnDetails = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
//[btnDetails addTarget:self action:#selector(prova) forControlEvents:UIControlEventTouchUpInside];
annotationView.rightCalloutAccessoryView=btnDetails;
return annotationView;
}
return nil;
}
The UIButtonTypeDetailDisclosure does not appear either (in other projects it does).

Resources