问题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个字符我的附件视图定位被搞砸了.
如何避免这个问题?
解决方法
苹果的指示是好的.要创建自己的标注,您应该遵循以下步骤:
- 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)
- }