【问题标题】:Custom font for MKAnnotationView CalloutMKAnnotationView 标注的自定义字体
【发布时间】:2015-07-19 00:40:22
【问题描述】:

幸运的是,MKAnnotationView 的标准标注视图满足了我们的需求 - titlesubtitleleftCalloutAccessoryViewrightCalloutAccessoryView

很遗憾,我们在应用中使用自定义字体,并希望将这些自定义字体扩展到这些标注。

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

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

【问题讨论】:

    标签: ios objective-c mkmapview mkannotationview mkmapviewdelegate


    【解决方案1】:

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

    1. 子类MKAnnotationView
    2. 覆盖 -layoutSubviews
    3. 选择MKAnnotationView MKAnnotationView时,将添加标注作为子视图。因此,我们可以递归地遍历我们的子类的子视图并找到我们想要修改的UILabel
    4. 就是这样!

    此方法的唯一缺点是,如果您的字体小于或大于预期的标准系统字体,您可以看到标注调整了它的大小。如果在呈现给用户之前进行所有调整,那就太好了。

    // 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]。确保在首次加载地图时关闭断点,因为如上所述,MKAnnotationViews 在选择之前没有任何子视图。在进行选择之前,启用断点,点击您的引脚,断开并打印出视图树。您会在树的最底部看到一个UILabel

    【讨论】:

    • 这可行,但是,我注意到注释视图的帧大小基于旧字体,然后根据新字体调整大小(带有动画)到新大小。有什么方法可以立即调整大小?
    • @JoshGafni 你有没有找到解决方案?
    【解决方案2】:

    因为我需要 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
        }
      }
    }
    

    【讨论】:

    • 我更新了我的答案以支持 Swift 3(删除了 var 参数)并稍微更新了语法。
    • 非常感谢兄弟非常需要这个:),我不得不自定义整个annotationView,通过你的逻辑实现
    猜你喜欢
    • 2011-12-22
    • 2010-11-23
    • 1970-01-01
    • 2010-12-06
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 2013-04-21
    • 1970-01-01
    相关资源
    最近更新 更多