我想定制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的示例:处理可能在注释视图界限之外的标注视图中的命中事件。
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的示例:动画:在用户选择注释视图时,动画化自定义标注视图的到达和删除。
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时,我找不到这个属性:
NSView *calloutView = self.calloutViewController.view;
如何访问标注气泡视图?
问题2)修改默认的标注泡
如前所述,所显示的默认标注具有标题、字幕和2个附件视图。我注意到,对于字符串的字体样式或气泡的颜色,我改变不了多少。此外,如果我的标题有超过24个字符,我的附件视图定位会变得混乱。我怎样才能避免这个问题?
发布于 2015-02-12 21:30:40
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)
}
https://stackoverflow.com/questions/28066623
复制相似问题