How to Customize the Title/Subtitle Font in Callout from Mkannotationview or Just Hide Them

Hide title and subtitle fields in MKAnnotationView

By default all you can do is add a detail view and left and right accessory views to the callout. I found a post online that goes into detail about creating a completely custom callout accessory view. It tells the system not to display a callout view, and then adds the custom callout view as a subview of the annotation view.

See this link: How To Completely Customise Your Map Annotations Callout Views

Custom font for MKAnnotationView Callout

If all you need is a custom font, you need to subclass MKAnnotationView, but you don't have to recreate all the behavior that you get for free with a standard MKAnnotationView. It's actually pretty easy.

  1. Subclass MKAnnotationView
  2. Override -layoutSubviews
  3. When an MKAnnotationView is selected, the callout is added as a subview. Therefore, we can recursively loop through our subclass' subviews and find the UILabel we wish to modify.
  4. That's it!

The only drawback with this method is that you can see the callout adjust it's size if your font is smaller or larger than the standard system font it was expecting. It'd be great if all the adjustments were made before being presented to the user.

// elsewhere, in a category on UIView.
// thanks to this answer: http://stackoverflow.com/a/25877372/607876
//
typedef void(^ViewBlock)(UIView *view, BOOL *stop);

@interface UIView (Helpers)
- (void)loopViewHierarchy:(ViewBlock)block;
@end

@implementation UIView (Helpers)

- (void)loopViewHierarchy:(ViewBlock)block {
BOOL stop = false;

if (block) {
block(self, &stop);
}

if (!stop) {
for (UIView* subview in self.subviews) {
[subview loopViewHierarchy:block];
}
}
}

@end

// then, in your MKAnnotationView subclass
//
@implementation CustomFontAnnotationView
- (void)layoutSubviews
{
// MKAnnotationViews only have subviews if they've been selected.
// short-circuit if there's nothing to loop over
if (!self.selected) {
return;
}

[self loopViewHierarchy:^(UIView *view, BOOL *stop) {
if ([view isKindOfClass:[UILabel class]]) {
*stop = true;
((UILabel *)view).font = {custom_font_name};
}
}];
}
@end

I inspected the view tree by first creating my MKAnnotationView subclass and setting a breakpoint in my overridden -layoutSubviews. In the debugger, I then issued po [self recursiveDescription]. Make sure to turn the breakpoint off when your map first loads, because as mentioned up above, MKAnnotationViews don't have any subviews until their selected. Before you make a selection, enable the breakpoint, tap your pin, break, and print out the view tree. You'll see a UILabel at the very bottom of the tree.

How can I display a MKPinAnnotationView data (e.g. title, subtitle) in a fixed-size component below the map instead of the popup above the pin?

You could try to add a UITapGestureRecognizer to your MKMapView. Then for the action, create a function that will display the View at the bottom.

GestureRecognizer added in viewDidLoad():

let showTap : UIGestureRecognizer = UITapGestureRecognizer(target: self, action: "tapShowView:")
myMapView.addGestureRecognizer(showTap)

Then your function could be something like this.

 func tapShowView(sender:UIGestureRecognizer) {

//Animate UIView in......

//Or just add your UIView.
let viewHeight = CGFloat(80)
let bottomView = UIView(frame: CGRect(x: 0, y: self.view.frame.height - viewHeight, width: self.view.frame.width, height: viewHeight))
bottomView.backgroundColor = .whiteColor()

//add buttons, navbar etc....

self.myMapView.addSubview(bottomView)
//OR if you add it in viewDidload and set to bottomView.hidden = true
bottomView.hidden = false

}

please ignore any syntax errors, I am not sitting at comp with Xcode on it. But this should give you a push. If you have any questions ill be back on when I wake up in a few hours(1:31 am here).. happy coding.

EDIT:

I think I miss read your question.....If you want to show the "BottomView" when user touches an annotation. You can call the "tapShowView" method from the MapViewDelegate method.

    func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {

if view.annotation!.isKindOfClass(FBAnnotationCluster) {

print("cluster selected")

} else {

print("single pin selected")
//Call method here to display BottomView.
self.tapShowView() //Edit tapShowView to remove sender
}

}

Then to prevent any callout showing when you touch an annotation in this delegate method..

   func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {

ADD:

 annotationView?.canShowCallout = true   

EDIT 2:
If you need to toggle the view when the user scrolls map etc. You can do that in the region did change delegate method.

 func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool){
//Just toggle the hidden property of the view.
BottomView.hidden = true
}

I would suggest you have a good look at the MKMapView delegate functions. There is a whole bunch of cool stuff you can do with them. Anytime you add something like a UITableView/UICollectionView/MKMapView etc... Take a few minutes to scroll through the delegate functions. Its really amazing how powerful some of the delegate functions are. If you need anything else, Ill be around the rest of the day.

How to create Custom MKAnnotationView and custom annotation title and subtitle

To create a custom annotation view (your replacement for the standard pin), you can just set the image property of the MKAnnotationView in the viewForAnnotation method:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
return nil;
}
else if ([annotation isKindOfClass:[YourAnnotationClassHere class]]) // use whatever annotation class you used when creating the annotation
{
static NSString * const identifier = @"MyCustomAnnotation";

MKAnnotationView* annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];

if (annotationView)
{
annotationView.annotation = annotation;
}
else
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:identifier];
}

annotationView.canShowCallout = NO; // set to YES if using customized rendition of standard callout; set to NO if creating your own callout from scratch
annotationView.image = [UIImage imageNamed:@"your-image-here.png"];

return annotationView;
}
return nil;
}

You might also want to adjust the centerOffset property to get the pin to line up precisely the way you want.

Regarding the customization of the callout, the easiest approach is to specify leftCalloutAccessoryView, rightCalloutAccessoryView and/or detailCalloutAccessoryView. This gives you a surprising degree of control, adding all sorts of images, labels, etc.

If you want to do a radical redesign of the callout, you can have viewForAnnotation set canShowCallout to NO and then respond to setSelected in your custom annotation view to show your own callout. While in Swift, see Customize MKAnnotation Callout View? for a few options for customizing the callouts.



Related Topics



Leave a reply



Submit