MKAnnotationView 标注的自定义字体
Custom font for MKAnnotationView Callout
幸运的是,MKAnnotationView
的标准标注视图满足我们的需求 - title
、subtitle
、leftCalloutAccessoryView
和 rightCalloutAccessoryView
。
不幸的是,我们在我们的应用程序中使用自定义字体,并希望将这些自定义字体扩展到这些标注。
MKAnnotationView 没有提供标准的方法来完成这个。
如何在 MKAnnotation
的标注视图中使用自定义字体?
如果您只需要自定义字体,则需要子类化 MKAnnotationView
,但您不必重新创建使用标准 MKAnnotationView
免费获得的所有行为。其实很简单。
- 子类
MKAnnotationView
- 覆盖 -layoutSubviews
- 选择
MKAnnotationView
时,标注将添加为子视图。因此,我们可以递归循环我们子类的子视图,找到我们想要修改的UILabel
。
- 就是这样!
此方法的唯一缺点是,如果您的字体小于或大于预期的标准系统字体,您可以看到标注调整其大小。如果所有的调整都在呈现给用户之前完成就好了。
// elsewhere, in a category on UIView.
// thanks to this answer:
//
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 在被选中之前没有任何子视图。在您做出选择之前,启用断点,点击您的引脚,断开并打印出视图树。您会在树的最底部看到 UILabel
。
因为我需要 Swift 版本 - 就在这里。
此外,您必须在 didAddSubview() 上调用 setNeedsLayout(),否则当您取消选择并重新选择注释时,不会调用 layoutSubviews() 并且标注具有其旧字体。
// elsewhere, in a category on UIView.
// thanks to this answer:
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
}
}
}
幸运的是,MKAnnotationView
的标准标注视图满足我们的需求 - title
、subtitle
、leftCalloutAccessoryView
和 rightCalloutAccessoryView
。
不幸的是,我们在我们的应用程序中使用自定义字体,并希望将这些自定义字体扩展到这些标注。
MKAnnotationView 没有提供标准的方法来完成这个。
如何在 MKAnnotation
的标注视图中使用自定义字体?
如果您只需要自定义字体,则需要子类化 MKAnnotationView
,但您不必重新创建使用标准 MKAnnotationView
免费获得的所有行为。其实很简单。
- 子类
MKAnnotationView
- 覆盖 -layoutSubviews
- 选择
MKAnnotationView
时,标注将添加为子视图。因此,我们可以递归循环我们子类的子视图,找到我们想要修改的UILabel
。 - 就是这样!
此方法的唯一缺点是,如果您的字体小于或大于预期的标准系统字体,您可以看到标注调整其大小。如果所有的调整都在呈现给用户之前完成就好了。
// elsewhere, in a category on UIView.
// thanks to this answer:
//
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 在被选中之前没有任何子视图。在您做出选择之前,启用断点,点击您的引脚,断开并打印出视图树。您会在树的最底部看到 UILabel
。
因为我需要 Swift 版本 - 就在这里。 此外,您必须在 didAddSubview() 上调用 setNeedsLayout(),否则当您取消选择并重新选择注释时,不会调用 layoutSubviews() 并且标注具有其旧字体。
// elsewhere, in a category on UIView.
// thanks to this answer:
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
}
}
}