Ответ 1
calloutViewController является частью пользовательского представления выносок для обработки событий. Вы не найдете его в MapKit или в другом месте.
Инструкции яблок хороши. Чтобы создать свою собственную выноску, вы должны выполнить следующие шаги:
1. Create custom MKAnnotationView or MAPinAnnotationView
2. Override setSelected and hitTest methods in your annotation
3. Create your own callout view
4. Override hitTest and pointInside in you callout view
5. Implement MapView delegate methods didSelectAnnotationView, didDeselectAnnotationView
Я закончил с этим решением, которое позволяет мне обрабатывать штрихи внутри вида выноски без потери выбора.
Аннотация
class MapPin: MKAnnotationView {
class var reuseIdentifier:String {
return "mapPin"
}
private var calloutView:MapPinCallout?
private var hitOutside:Bool = true
var preventDeselection:Bool {
return !hitOutside
}
convenience init(annotation:MKAnnotation!) {
self.init(annotation: annotation, reuseIdentifier: MapPin.reuseIdentifier)
canShowCallout = false;
}
override func setSelected(selected: Bool, animated: Bool) {
let calloutViewAdded = calloutView?.superview != nil
if (selected || !selected && hitOutside) {
super.setSelected(selected, animated: animated)
}
self.superview?.bringSubviewToFront(self)
if (calloutView == nil) {
calloutView = MapPinCallout()
}
if (self.selected && !calloutViewAdded) {
addSubview(calloutView!)
}
if (!self.selected) {
calloutView?.removeFromSuperview()
}
}
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
var hitView = super.hitTest(point, withEvent: event)
if let callout = calloutView {
if (hitView == nil && self.selected) {
hitView = callout.hitTest(point, withEvent: event)
}
}
hitOutside = hitView == nil
return hitView;
}
}
Вид выноска
class MapPinCallout: UIView {
override func hitTest(var point: CGPoint, withEvent event: UIEvent?) -> UIView? {
let viewPoint = superview?.convertPoint(point, toView: self) ?? point
let isInsideView = pointInside(viewPoint, withEvent: event)
var view = super.hitTest(viewPoint, withEvent: event)
return view
}
override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
return CGRectContainsPoint(bounds, point)
}
}
Если вам нужно что-то еще, но кнопки будут реагировать в выноске, добавьте код для обработки штрихов в определенных представлениях, прежде чем hitTest вернет представление
if calloutState == .Expanded && CGRectContainsPoint(tableView.frame, viewPoint) {
view = tableView.hitTest(convertPoint(viewPoint, toView: tableView), withEvent: event)
}
Методы делегата
func mapView(mapView: MKMapView!, didSelectAnnotationView view: MKAnnotationView!) {
if let mapPin = view as? MapPin {
updatePinPosition(mapPin)
}
}
func mapView(mapView: MKMapView!, didDeselectAnnotationView view: MKAnnotationView!) {
if let mapPin = view as? MapPin {
if mapPin.preventDeselection {
mapView.selectAnnotation(view.annotation, animated: false)
}
}
}
func updatePinPosition(pin:MapPin) {
let defaultShift:CGFloat = 50
let pinPosition = CGPointMake(pin.frame.midX, pin.frame.maxY)
let y = pinPosition.y - defaultShift
let controlPoint = CGPointMake(pinPosition.x, y)
let controlPointCoordinate = mapView.convertPoint(controlPoint, toCoordinateFromView: mapView)
mapView.setCenterCoordinate(controlPointCoordinate, animated: true)
}