作者:chingueen_306 | 来源:互联网 | 2023-05-25 18:05
我想自定义iOS8 MapView Callout气泡,点击MKAnnotationView时可以看到它.默认气泡有点限制(只有标题,副标题和2个附件视图)所以我很难找到替代解决方案.这里有两种可能的方式和我面临的相关问题:
问题1)创建一个CUSTOM CALLOUT BUBBLE
挖掘Apple文档我发现了这个:
当您使用自定义视图而不是标准标注时,您需要做额外的工作以确保您的标注在用户与之交互时显示和隐藏.以下步骤概述了创建包含按钮的自定义标注的过程:
设计表示自定义标注的NSView或UIView子类.子类可能需要实现drawRect:方法来绘制自定义内容.创建一个视图控制器,初始化标注视图并执行与按钮相关的操作.在注释视图中,实现hitTest:以响应注释视图边界之外但在callout视图边界内的命中,如清单6-7所示.在注释视图中,实现setSelected:animated:当用户单击或点击它时,将您的标注视图添加为注释视图的子视图.如果callout视图在用户选择它时已经可见,则setSelected:方法应该从注释视图中删除callout子视图(参见清单6-8).在注释视图的initWithAnnotation:方法中,将canShowCallout属性设置为NO以防止在用户选择注释时地图显示标准标注.清单6-7显示了一个实现hitTest的示例:处理callout视图中可能超出注释视图边界的命中.
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:animated:的示例,用于在用户选择注释视图时为自定义标注视图的到达和解除设置动画.
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)修改默认的CALLOUT BUBBLE
如前所述,显示的默认标注具有标题,副标题和2个附件视图.我注意到我无法改变字符串的字体样式或泡泡的颜色.此外,如果我的标题有超过24个字符我的配件视图定位搞砸了.我该如何避免这个问题?
1> Maksim Bolsh..:
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)
}
}
如果你需要别的东西,但按钮在callout中响应,在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)
}