Ios MKAnnotationView标注的自定义字体

Ios MKAnnotationView标注的自定义字体,ios,objective-c,mkmapview,mkannotationview,mkmapviewdelegate,Ios,Objective C,Mkmapview,Mkannotationview,Mkmapviewdelegate,幸运的是,MKAnnotationView的标准callout视图满足了我们的需求—标题,副标题,左callout访问视图,以及右callout访问视图 不幸的是,我们在应用程序中使用自定义字体,并希望将这些自定义字体扩展到这些标注 MKAnnotationView没有提供实现这一点的标准方法 如何在MKAnnotation的标注视图中使用自定义字体?如果您只需要自定义字体,则需要将MKAnnotationView子类化,但不必重新创建使用标准MKAnnotationView免费获得的所有行为。

幸运的是,
MKAnnotationView
的标准callout视图满足了我们的需求—
标题
副标题
左callout访问视图
,以及
右callout访问视图

不幸的是,我们在应用程序中使用自定义字体,并希望将这些自定义字体扩展到这些标注

MKAnnotationView没有提供实现这一点的标准方法


如何在
MKAnnotation
的标注视图中使用自定义字体?

如果您只需要自定义字体,则需要将
MKAnnotationView
子类化,但不必重新创建使用标准
MKAnnotationView
免费获得的所有行为。其实很简单

  • 子类
    MKAnnotationView
  • 覆盖-布局子视图
  • 选择
    MKAnnotationView
    时,详图索引将作为子视图添加。因此,我们可以递归地遍历子类的子视图,并找到我们想要修改的
    UILabel
  • 就这样 此方法的唯一缺点是,如果您的字体小于或大于预期的标准系统字体,则可以看到详图索引调整其大小。如果所有的调整都在呈现给用户之前完成,那就太好了

    // elsewhere, in a category on UIView.
    // thanks to this answer: http://stackoverflow.com/a/25877372/607876
    //
    typedef void(^ViewBlock)(UIView *view, BOOL *stop);
    
    @interface UIView (Helpers)
    - (void)loopViewHierarchy:(ViewBlock)block;
    @end
    
    @implementation UIView (Helpers)
    
    - (void)loopViewHierarchy:(ViewBlock)block {
        BOOL stop = false;
    
        if (block) {
            block(self, &stop);
        }
    
        if (!stop) {
            for (UIView* subview in self.subviews) {
                [subview loopViewHierarchy:block];
            }
        }
    }
    
    @end
    
    // then, in your MKAnnotationView subclass
    //
    @implementation CustomFontAnnotationView
    - (void)layoutSubviews
    {
        // MKAnnotationViews only have subviews if they've been selected.
        // short-circuit if there's nothing to loop over
        if (!self.selected) {
            return;
        }
    
        [self loopViewHierarchy:^(UIView *view, BOOL *stop) {
            if ([view isKindOfClass:[UILabel class]]) {
                *stop = true;
                ((UILabel *)view).font = {custom_font_name};
            }
        }];
    }
    @end
    

    我首先创建了我的
    MKAnnotationView
    子类,并在覆盖的
    -layoutSubviews
    中设置了一个断点,从而检查了视图树。在调试器中,我随后发布了
    po[self recursiveDescription]
    。确保在首次加载地图时关闭断点,因为如上所述,
    MKAnnotationView
    s在选择子视图之前没有任何子视图。在进行选择之前,启用断点,点击pin,断开并打印视图树。您将在树的最底部看到一个
    UILabel

    因为我需要Swift版本-在这里。 此外,您还必须在didAddSubview()上调用setNeedsLayout(),因为否则,当您取消选择并重新选择注释layoutSubviews()时,不会调用该注释,并且该注释具有其旧字体

    // elsewhere, in a category on UIView.
    // thanks to this answer: http://stackoverflow.com/a/25877372/607876
    
    typealias ViewBlock = (_ view: UIView) -> Bool
    
    extension UIView {
      func loopViewHierarchy(block: ViewBlock?) {
    
        if block?(self) ?? true {
          for subview in subviews {
            subview.loopViewHierarchy(block: block)
          }
        }
      }
    }
    
    // then, in your MKAnnotationView subclass
    
    class CustomFontAnnotationView: MKAnnotationView {
    
      override func didAddSubview(_ subview: UIView) {
        if isSelected {
          setNeedsLayout()
        }
      }
    
      override func layoutSubviews() {
    
        // MKAnnotationViews only have subviews if they've been selected.
        // short-circuit if there's nothing to loop over
    
        if !isSelected {
          return
        }
    
        loopViewHierarchy { (view: UIView) -> Bool in
          if let label = view as? UILabel {
            label.font = labelFont
            return false
          }
          return true
        }
      }
    }
    

    但是,我注意到注释视图的帧大小基于旧字体,然后(通过动画)根据新字体调整为新大小。有什么方法可以让它立即调整到合适的大小吗?@JoshGafni你找到解决方案了吗?我更新了我的答案,以支持Swift 3(删除的var参数),并稍微更新了语法。非常感谢brother非常需要它:),我必须定制整个注释视图,通过你的逻辑实现