如何在 Objective-C 中实现 MKClusterAnnotations?

Jac*_*y.S 4 objective-c mkmapview mkannotation ios

我正在尝试为我的 Apple 地图上彼此非常接近的注释创建集群视图。我知道 Apple 在 iOS 11 中推出了原生集群视图套件,但我在网上找到的所有教程都是用 Swift 编写的。我希望有人可以教我或推荐我任何我可以阅读的教程,以了解如何在 Objective-C 中实现集群注释。

我的想法是创建一个ClusterView类,它继承MKAnnotationView类,然后在mapView控制器中创建ClusterView的实例。

我已经阅读了苹果的文档,它只为您提供了我可能需要调用的函数,但没有解释如何使用它们,这是苹果文档的链接: https: //developer.apple.com/文档/mapkit/mkclusterannotation?language=objc

任何帮助,将不胜感激!

Rob*_*Rob 6

以下是基本步骤:

\n\n
    \n
  1. 定义注释视图,指定clusteringIdentifiercollisionMode

    \n\n
    //  CustomAnnotationView.h\n\n@import MapKit;\n\n@interface CustomAnnotationView : MKMarkerAnnotationView\n\n@end\n
    Run Code Online (Sandbox Code Playgroud)\n\n

    \n\n
    //  CustomAnnotationView.m\n\n#import "CustomAnnotationView.h"\n\nstatic NSString *identifier = @"com.domain.clusteringIdentifier";\n\n@implementation CustomAnnotationView\n\n- (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {\n    if ((self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier])) {\n        self.clusteringIdentifier = identifier;\n        self.collisionMode = MKAnnotationViewCollisionModeCircle;\n    }\n\n    return self;\n}\n\n- (void)setAnnotation:(id<MKAnnotation>)annotation {\n    [super setAnnotation:annotation];\n\n    self.clusteringIdentifier = identifier;\n}\n\n@end\n
    Run Code Online (Sandbox Code Playgroud)
  2. \n
  3. 或者,如果需要,您可以定义自己的集群注释视图,指定displayPrioritycollisionMode。这还更新了集群的图像以指示有多少注释被集群:

    \n\n
    //  ClusterAnnotationView.h\n\n@import MapKit;\n\n@interface ClusterAnnotationView : MKAnnotationView\n\n@end\n
    Run Code Online (Sandbox Code Playgroud)\n\n

    \n\n
    //  ClusterAnnotationView.m\n\n#import "ClusterAnnotationView.h"\n\n@implementation ClusterAnnotationView\n\n- (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {\n    if ((self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier])) {\n        self.displayPriority = MKFeatureDisplayPriorityDefaultHigh;\n        self.collisionMode = MKAnnotationViewCollisionModeCircle;\n    }\n\n    return self;\n}\n\n- (void)setAnnotation:(id<MKAnnotation>)annotation {\n    super.annotation = annotation;\n    [self updateImage:annotation];\n}\n\n- (void)updateImage:(MKClusterAnnotation *)cluster {\n    if (!cluster) {\n        self.image = nil;\n        return;\n    }\n\n    CGRect rect = CGRectMake(0, 0, 40, 40);\n    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:rect.size];\n    self.image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {\n        // circle\n\n        [[UIColor blueColor] setFill];\n        [[UIColor whiteColor] setStroke];\n\n        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:rect];\n        path.lineWidth = 0.5;\n        [path fill];\n        [path stroke];\n\n        // count\n\n        NSString *text = [NSString stringWithFormat:@"%ld", (long) cluster.memberAnnotations.count];\n        NSDictionary<NSAttributedStringKey, id> *attributes = @{\n            NSFontAttributeName: [UIFont preferredFontForTextStyle: UIFontTextStyleBody],\n            NSForegroundColorAttributeName: [UIColor whiteColor]\n                                                                };\n        CGSize size = [text sizeWithAttributes:attributes];\n        CGRect textRect = CGRectMake(rect.origin.x + (rect.size.width  - size.width)  / 2,\n                                     rect.origin.y + (rect.size.height - size.height) / 2,\n                                     size.width,\n                                     size.height);\n        [text drawInRect:textRect withAttributes:attributes];\n    }];\n}\n\n@end\n
    Run Code Online (Sandbox Code Playgroud)\n\n

    如果您不想,则不必为集群创建自己的子类。但这只是说明了如何完全控制集群的外观(如果您选择这样做)。

  4. \n
  5. 然后你的视图控制器只需要注册适当的类,你\xe2\x80\x99就完成了(不需要地图视图委托):

    \n\n
    [self.mapView registerClass:[CustomAnnotationView class] forAnnotationViewWithReuseIdentifier:MKMapViewDefaultAnnotationViewReuseIdentifier];\n
    Run Code Online (Sandbox Code Playgroud)\n\n

    如果您想使用自定义集群视图,您也可以注册它:

    \n\n
    [self.mapView registerClass:[ClusterAnnotationView class] forAnnotationViewWithReuseIdentifier:MKMapViewDefaultClusterAnnotationViewReuseIdentifier];\n
    Run Code Online (Sandbox Code Playgroud)\n\n

    例如:

    \n\n
    //  ViewController.m\n\n#import \xe2\x80\x9cViewController.h"\n\n@import MapKit;\n\n#import "CustomAnnotationView.h"\n#import "ClusterAnnotationView.h"\n\n@interface ViewController ()\n@property (weak, nonatomic) IBOutlet MKMapView *mapView;\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    [self configureMapView];\n}\n\n- (void)configureMapView {\n    self.mapView.userTrackingMode = MKUserTrackingModeFollow;\n\n    [self.mapView registerClass:[CustomAnnotationView class] forAnnotationViewWithReuseIdentifier:MKMapViewDefaultAnnotationViewReuseIdentifier];\n    [self.mapView registerClass:[ClusterAnnotationView class] forAnnotationViewWithReuseIdentifier:MKMapViewDefaultClusterAnnotationViewReuseIdentifier];\n}\n\n// I\xe2\x80\x99m going to search for restaurants and add annotations for those,\n// but do whatever you want\n\n- (void)performSearch {\n    MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];\n    request.naturalLanguageQuery = @"restaurant";\n    request.region = self.mapView.region;\n\n    MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request];\n    [search startWithCompletionHandler:^(MKLocalSearchResponse * _Nullable response, NSError * _Nullable error) {\n        if (error) {\n            NSLog(@"%@", error);\n            return;\n        }\n\n        for (MKMapItem *mapItem in response.mapItems) {\n            MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];\n            annotation.coordinate = mapItem.placemark.coordinate;\n            annotation.title = mapItem.name;\n            annotation.subtitle = mapItem.placemark.thoroughfare;\n            [self.mapView addAnnotation:annotation];\n        }\n    }];\n}\n\n@end\n
    Run Code Online (Sandbox Code Playgroud)
  6. \n
\n\n

得出:

\n\n

演示

\n