自定义iOS8标注泡沫(Swift)

前端之家收集整理的这篇文章主要介绍了自定义iOS8标注泡沫(Swift)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我想定制iOS8 MapView标注泡泡,当您点击MKAnnotationView时可以看到它.默认气泡是有限制的(只有标题,副标题和2附件视图),所以我很难找到一个替代解决方案.这里有两种可能的方法和我面临的相对问题:

问题1)创建一个自定义的呼叫泡泡

挖掘Apple documentation我发现这个:

When you use a custom view instead of a standard callout,you need to
do extra work to make sure your callout shows and hides appropriately
when users interact with it. The steps below outline the process for
creating a custom callout that contains a button:

Design an NSView or UIView subclass that represents the custom
callout. It’s likely that the subclass needs to implement the
drawRect: method to draw your custom content. Create a view controller
that initializes the callout view and performs the action related to
the button. In the annotation view,implement hitTest: to respond to
hits that are outside the annotation view’s bounds but inside the
callout view’s bounds,as shown in Listing 6-7. In the annotation
view,implement setSelected:animated: to add your callout view as a
subview of the annotation view when the user clicks or taps it. If the
callout view is already visible when the user selects it,the
setSelected: method should remove the callout subview from the
annotation view (see Listing 6-8). In the annotation view’s
initWithAnnotation: method,set the canShowCallout property to NO to
prevent the map from displaying the standard callout when the user
selects the annotation. Listing 6-7 shows an example of implementing
hitTest: to handle hits in the callout view that might be outside the
bounds of the annotation view.

Listing 6-7  Responding to hits within a custom callout
- (NSView *)hitTest:(NSPoint)point
{
    NSView *hitView = [super hitTest:point];
    if (hitView == nil && self.selected) {
        NSPoint pointInAnnotationView = [self.superview convertPoint:point toView:self];
        NSView *calloutView = self.calloutViewController.view;
        hitView = [calloutView hitTest:pointInAnnotationView];
    }
    return hitView;
}

Listing 6-8 shows an example of implementing setSelected:animated: to
animate the arrival and dismissal of a custom callout view when the
user selects the annotation view.

Listing 6-8  Adding and removing a custom callout view
- (void)setSelected:(BOOL)selected
{
    [super setSelected:selected];

    // Get the custom callout view.
    NSView *calloutView = self.calloutViewController.view;
    if (selected) {
        NSRect annotationViewBounds = self.bounds;
        NSRect calloutViewFrame = calloutView.frame;
      // Center the callout view above and to the right of the annotation view.
        calloutViewFrame.origin.x = -(NSWidth(calloutViewFrame) - NSWidth(annotationViewBounds)) * 0.5;
        calloutViewFrame.origin.y = -NSHeight(calloutViewFrame) + 15.0;
        calloutView.frame = calloutViewFrame;

        [self addSubview:calloutView];
    } else {
        [calloutView.animator removeFromSuperview];
    }
}

现在,当我尝试将此Objective-C代码转换为Swift时,我找不到此属性

NSView *calloutView = self.calloutViewController.view;

如何访问标注气泡视图?

问题2)修改默认呼叫泡泡

如前所述,显示的默认标注包括标题,副标题和2个附件视图.我注意到我不能改变字符串的字体风格或泡沫的颜色.另外如果我的标题有超过24个字符我的附件视图定位被搞砸了.
如何避免这个问题?

解决方法

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)
}

猜你在找的iOS相关文章