MKAnnotationView标注的自定义字体

时间:2015-05-08 07:19:55

标签: ios objective-c mkmapview mkannotationview mkmapviewdelegate

幸运的是,MKAnnotationView的标准标注视图符合我们的需求 - titlesubtitleleftCalloutAccessoryViewrightCalloutAccessoryView

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

MKAnnotationView没有提供完成此任务的标准方法。

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

2 个答案:

答案 0 :(得分:7)

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

// 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
    }
  }
}

答案 1 :(得分:1)

如果你需要的只是一个自定义字体,你需要继承MKAnnotationView,但你不必重新创建使用标准MKAnnotationView免费获得的所有行为。这实际上非常简单。

  1. 子类MKAnnotationView
  2. 覆盖-layoutSubviews
  3. 选择MKAnnotationView时,会将标注添加为子视图。因此,我们可以递归循环遍历子类的子视图,并找到我们希望修改的UILabel
  4. 就是这样!
  5. 此方法的唯一缺点是,如果字体小于或大于预期的标准系统字体,则可以看到标注调整其大小。如果在呈现给用户之前进行了所有调整,那就太棒了。

    // 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在选择之前没有任何子视图。在进行选择之前,启用断点,点击引脚,中断并打印视图树。你会在树的最底部看到UILabel