自定义MKAnnotation标注视图?

时间:2015-06-11 23:54:01

标签: ios swift mapkit

我有MKPointAnnotation

let ann = MKPointAnnotation()
self.ann.coordinate = annLoc
self.ann.title = "Customize me"
self.ann.subtitle = "???"
self.mapView.addAnnotation(ann)

看起来像这样:

enter image description here

如何自定义此标注视图以创建自己的视图而非预定义的视图?

3 个答案:

答案 0 :(得分:66)

首先应该注意,只需调整系统提供的标注属性,即可自定义右侧和左侧附件(通过rightCalloutAccessoryViewleftCalloutAccessoryView),即可对标注进行最简单的更改。您可以在viewForAnnotation中执行该配置。

在iOS 9中,我们现在可以访问detailCalloutAccessoryView,用可能视觉丰富的视图替换标注的副标题,同时仍然享受标注气泡的自动再现(使用自动布局使这更容易)。

例如,这是一个标注,使用MKSnapshotter为细节标注附件中的图像视图提供图像,如WWDC 2015视频What's New in MapKit中所示:

enter image description here

您可以通过以下方式实现此目标:

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation is MKUserLocation {
        return nil
    }

    let identifier = "MyCustomAnnotation"

    var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
    if annotationView == nil {
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        annotationView?.canShowCallout = true
    } else {
        annotationView!.annotation = annotation
    }

    configureDetailView(annotationView!)

    return annotationView
}

func configureDetailView(annotationView: MKAnnotationView) {
    let width = 300
    let height = 200

    let snapshotView = UIView()
    let views = ["snapshotView": snapshotView]
    snapshotView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[snapshotView(300)]", options: [], metrics: nil, views: views))
    snapshotView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[snapshotView(200)]", options: [], metrics: nil, views: views))

    let options = MKMapSnapshotOptions()
    options.size = CGSize(width: width, height: height)
    options.mapType = .SatelliteFlyover
    options.camera = MKMapCamera(lookingAtCenterCoordinate: annotationView.annotation!.coordinate, fromDistance: 250, pitch: 65, heading: 0)

    let snapshotter = MKMapSnapshotter(options: options)
    snapshotter.startWithCompletionHandler { snapshot, error in
        if snapshot != nil {
            let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
            imageView.image = snapshot!.image
            snapshotView.addSubview(imageView)
        }
    }

    annotationView.detailCalloutAccessoryView = snapshotView
}

如果您正在寻找更激进的重新设计标注或需要支持9之前的iOS版本,则需要更多工作。该过程需要(a)禁用默认标注; (b)当用户点击现有的注释视图(即地图上的视觉引脚)时添加自己的视图。

复杂性随后出现在标注的设计中,您必须绘制所需的所有内容。例如。如果你想绘制一个气泡来产生呼唤的弹出感觉,你必须自己做。但是如果熟悉如何绘制形状,图像,文本等,您应该能够渲染出一个能够实现所需UX的标注:

custom callout

只需将视图添加为注释视图本身的子视图,并相应地调整其约束:

func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
    let calloutView = ...
    calloutView.translatesAutoresizingMaskIntoConstraints = false
    calloutView.backgroundColor = UIColor.lightGrayColor()
    view.addSubview(calloutView)

    NSLayoutConstraint.activateConstraints([
        calloutView.bottomAnchor.constraintEqualToAnchor(view.topAnchor, constant: 0),
        calloutView.widthAnchor.constraintEqualToConstant(60),
        calloutView.heightAnchor.constraintEqualToConstant(30),
        calloutView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor, constant: view.calloutOffset.x)
    ])
}

有关创建自己的标注视图的示例,请参阅https://github.com/robertmryan/CustomMapViewAnnotationCalloutSwift。这只会添加两个标签,但它说明了您可以根据需要绘制任何形状的气泡,使用约束来指定标注的大小等。

答案 1 :(得分:2)

使用classtype MKAnnotationView

创建Cocoa文件

CustomeAnnotationView.h文件

@interface CustomeAnnotationView : MKAnnotationView
@property (strong, nonatomic) UIButton *buttonCustomeCallOut;
- (void)setSelected:(BOOL)selected animated:(BOOL)animated;
@end

CustomeAnnotationView.m文件

@implementation CustomeAnnotationView

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}


- (void)setSelected:(BOOL)selected animated:(BOOL)animated{

    [super setSelected:selected animated:animated];

    if(selected)
    {



            self.buttonCustomeCallOut = [UIButton buttonWithType:UIButtonTypeCustom];//iconShare//iconShareBlue

            [self.buttonCustomeCallOut addTarget:self action:@selector(buttonHandlerCallOut:) forControlEvents:UIControlEventTouchDown];
        [self.buttonCustomeCallOut setBackgroundColor:[UIColor blueColor]];

            [self.buttonCustomeCallOut setFrame:CGRectMake(-40,-80, 100, 100)];



            [self addSubview:self.buttonCustomeCallOut];

        [self.buttonCustomeCallOut setUserInteractionEnabled:YES];
    }
    else
    {
        //Remove your custom view...
        [self.buttonCustomeCallOut setUserInteractionEnabled:NO];
        [self.buttonCustomeCallOut removeFromSuperview];

        self.buttonCustomeCallOut=nil;
    }
}
-(void)buttonHandlerCallOut:(UIButton*)sender{
    NSLog(@"Annotation Clicked");
}

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    UIView* v = [super hitTest:point withEvent:event];
    if (v != nil)
    {
        [self.superview bringSubviewToFront:self];
    }
    return v;
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
    CGRect rec = self.bounds;
    BOOL isIn = CGRectContainsPoint(rec, point);
    if(!isIn)
    {
        for (UIView *v in self.subviews)
        {
            isIn = CGRectContainsPoint(v.frame, point);
            if(isIn)
                break;
        }
    }
    return isIn;
}
@end

将此代码放在您想要创建客户呼叫的位置

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    static NSString *identifier = @"CustAnnotation";

        CustomeAnnotationView *annotationView = (CustomeAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        if (annotationView == nil) {
            annotationView = [[CustomeAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
        }

        annotationView.enabled = YES;
        annotationView.canShowCallout = NO;
        annotationView.centerOffset = CGPointMake(0,-10);//-18

        return annotationView;
}

答案 2 :(得分:1)

无需创建MKAnnotationView Custom类只需创建一个空视图.xib并设计.xib作为您的要求。在UIView swift类中编写您的企业登录信息。

上添加视图

func mapView(_ mapView:MKMapView,viewFor annotation:MKAnnotation) - &gt; MKAnnotationView? {

...

}

方法如annotationView?.detailCalloutAccessoryView = customView

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    let annotationIdentifier = "AnnotationIdentifier"
    var annotationView: MKAnnotationView?
    if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) {
        annotationView = dequeuedAnnotationView
        annotationView?.annotation = annotation
    } else {
        annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
    }
    if let annotation = annotation as? HPAnnotation {
       annotationView?.canShowCallout = true
       let customView = Bundle.main.loadNibNamed("HPAnnotationView", owner: self, options: nil)?.first as! HPAnnotationView
       customView.labelName.text = annotation.annotationTitle
       annotationView?.detailCalloutAccessoryView = customView
    }
    return annotationView
 }

如果你想在callout视图上显示动态值,那么首先制作MKAnnotation自定义类,你可以根据需要传递对象。

import MapKit
import AddressBook
import UIKit

class HPAnnotation: NSObject, MKAnnotation {

   let title: String?
   let annotationTitle: String
   init(title: String, annotationTitle: String = "") {
      self.title = title
      self.annotationTitle = annotationTitle
   }

   var subtitle: String? {
     return details
   }

}

并在创建注释时传递值

 for index in 0..<searchPeopleArray.count {
    let annotation = HPAnnotation(title: "", annotationTitle: "")
    mapView.addAnnotation(annotation)
}

N.B:这里HPAnnotationView是我的自定义视图类和xib名称。 HPAnnotation是我的自定义MKAnnotation。