Настроить просмотр выноски MKAnnotation?

У меня есть MKPointAnnotation:

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

Это выглядит так:

введите описание изображения здесь

Как я могу настроить это представление выноски, чтобы создать мое собственное представление вместо предопределенного?

3 ответа

Решение

Прежде всего следует отметить, что простейшие изменения в выноске возможны путем простой настройки свойств предоставляемой системой выноски, но путем настройки правого и левого аксессуаров (через rightCalloutAccessoryView а также leftCalloutAccessoryView). Вы можете сделать эту конфигурацию в viewForAnnotation,

В iOS 9 у нас теперь есть доступ к detailCalloutAccessoryView который заменяет субтитры выноски потенциально визуально насыщенным представлением, в то же время наслаждаясь автоматическим воспроизведением всплывающей подсказки (использование автоматической разметки делает это проще).

Например, здесь выноска, которая использовала MKSnapshotter предоставить изображение для просмотра изображения в дополнительном элементе выноски, как показано в видео WWDC 2015 Что нового в MapKit:

Вы можете достичь этого с помощью чего-то вроде:

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
}

Если вы ищете более радикальную переработку выноски или вам нужна поддержка версий iOS до 9, это займет больше времени. Процесс влечет за собой (а) отключение выноски по умолчанию; и (б) добавление вашего собственного вида, когда пользователь нажимает на существующий вид аннотации (то есть визуальный значок на карте).

Сложность тогда возникает в дизайне выноски, где вы должны нарисовать все, что вы хотите, видимым. Например, если вы хотите нарисовать пузырь, чтобы всплыть ощущение вызова, вы должны сделать это самостоятельно. Но, имея некоторое представление о том, как рисовать фигуры, изображения, текст и т. Д., Вы сможете отобразить выноску, которая достигает желаемого UX:

пользовательский вынос

Просто добавьте представление как подпредставление самого представления аннотации и соответствующим образом скорректируйте его ограничения:

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 для примера создания собственного представления выноски. Это добавляет только две метки, но это иллюстрирует тот факт, что вы можете нарисовать пузырь любой фигуры, которую вы хотите, использовать ограничения для определения размера выноски и т. Д.

Нет необходимости создавать пользовательский класс MKAnnotationView, просто создайте пустое представление.xib и спроектируйте.xib как ваше требование. Напишите свой бизнес логин в классе UIView Swift.

Добавить вид на

func mapView(_ mapView: MKMapView, viewFor аннотация: MKAnnotation) -> 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
 }

Если вы хотите, чтобы динамическое значение отображалось в представлении выноски, сначала создайте пользовательский класс 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)
}

NB. Здесь HPAnnotationView - это мой пользовательский класс представления и имя XIB. HPAnnotation - это мой пользовательский MKAnnotation.

Создать файл какао с классическим типом MKAnnotationView

Файл 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;
}
Другие вопросы по тегам