首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >定制iOS8标注泡(Swift)

定制iOS8标注泡(Swift)
EN

Stack Overflow用户
提问于 2015-01-21 11:54:37
回答 1查看 8.8K关注 0票数 13

我想定制iOS8 MapView标注泡沫,它在点击MKAnnotationView时会被可视化。默认气泡是有点限制(只有标题,副标题和2个附件视图),所以我正在努力寻找另一个解决方案。这里有两种可能的方法和我面临的相关问题:

问题1)创建自定义的标注泡

挖掘Apple documentation,我发现了以下内容:

当您使用自定义视图而不是标准标注时,您需要做额外的工作,以确保您的标注在用户与其交互时适当地显示和隐藏。下面的步骤概述了创建包含按钮的自定义标注的过程: 设计一个表示自定义标注的NSView或UIView子类。子类可能需要实现drawRect:方法来绘制自定义内容。创建一个视图控制器,该控制器初始化callout视图并执行与按钮相关的操作。在注释视图中,实现hitTest:以响应注释视图边界之外但在标注视图边界内的命中,如清单6-7所示。在注释视图中,实现setSelected:动画:在用户单击或点击注释视图时,将其添加为注释视图的子视图。如果用户选择callout视图时已经可见,那么setSelected:方法应该从注释视图中删除callout子视图(参见清单6-8)。在注释视图的initWithAnnotation:方法中,将canShowCallout属性设置为NO,以防止映射在用户选择注释时显示标准标注。清单6-7展示了一个实现hitTest的示例:处理可能在注释视图界限之外的标注视图中的命中事件。

代码语言:javascript
运行
复制
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;
}

清单6-8展示了一个实现setSelected的示例:动画:在用户选择注释视图时,动画化自定义标注视图的到达和删除。

代码语言:javascript
运行
复制
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代码转换为Swift时,我找不到这个属性:

代码语言:javascript
运行
复制
NSView *calloutView = self.calloutViewController.view;

如何访问标注气泡视图?

问题2)修改默认的标注泡

如前所述,所显示的默认标注具有标题、字幕和2个附件视图。我注意到,对于字符串的字体样式或气泡的颜色,我改变不了多少。此外,如果我的标题有超过24个字符,我的附件视图定位会变得混乱。我怎样才能避免这个问题?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-02-12 21:30:40

calloutViewController是处理事件的自定义标注视图的一部分。你在MapKit或其他地方找不到它。

苹果的说明很好。要创建自己的标注,您应该遵循以下步骤:

代码语言:javascript
运行
复制
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

我最终得到了这样的解决方案,它允许我在不丢失选择的情况下处理内部标注视图中的触摸。

注解

代码语言:javascript
运行
复制
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;
    }
}

标注视图

代码语言:javascript
运行
复制
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返回视图之前,添加代码来处理特定视图中的触摸

代码语言:javascript
运行
复制
if calloutState == .Expanded && CGRectContainsPoint(tableView.frame, viewPoint) {
    view = tableView.hitTest(convertPoint(viewPoint, toView: tableView), withEvent: event)
}

委托方法

代码语言:javascript
运行
复制
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)
}
票数 19
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28066623

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档