将MKPolygon作为MKMapView的覆盖层添加时遇到的问题

5
嗨,正如标题所说,我在向MKMapView添加MKPolygon叠加层时遇到了困难。以下是相关代码:
ParkingMapViewContoller.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>


@interface ParkingMapViewController : UIViewController <MKMapViewDelegate> {
    MKMapView *mapView;
}

@property (nonatomic, retain) IBOutlet MKMapView *mapView;


-(void)loadAnnotations;
-(void)showCurrentLocationButtonTapped:(id)sender;


@end

ParkingMapViewController.m

//...
#import "ParkingRegionOverlay.h"
//...
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"%@",self.title);

    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:100 target:self action:@selector(showCurrentLocationButtonTapped:)];

    /*MKMapPoint points[3] = {{38.53607,-121.765793}, {38.537606,-121.768379}, {38.53487,-121.770578}};
    MKPolygon *polygon = [MKPolygon polygonWithPoints:points count:3];*/

    ParkingRegionOverlay *polygon = [[ParkingRegionOverlay alloc] initialize];
    [mapView addOverlay:polygon];

    [self loadAnnotations];

    CLLocationCoordinate2D centerCoord = { UCD_LATITUDE, UCD_LONGITUDE };
    [mapView setCenterCoordinate:centerCoord zoomLevel:13 animated:NO]; //from "MKMapView+ZoomLevel.h"
}
//...

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
    NSLog(@"in viewForOverlay!");

    if ([overlay isKindOfClass:[MKPolygon class]])

    {

        MKPolygonView*    aView = [[[MKPolygonView alloc] initWithPolygon:(MKPolygon*)overlay] autorelease];

        aView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];

        aView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];

        aView.lineWidth = 3;

        return aView;

    }
    return nil;
}
//...

ParkingRegionOverlay.h

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>


@interface ParkingRegionOverlay : NSObject <MKOverlay> {
    //CLLocationCoordinate2D origin;
    MKPolygon *polygon;

    //MKMapRect rect;
}

//@property (nonatomic) CLLocationCoordinate2D origin;
@property (nonatomic, retain) MKPolygon *polygon;

//@property (nonatomic) MKMapRect rect;

-(ParkingRegionOverlay*)initialize;
-(MKMapRect)boundingMapRect;
-(CLLocationCoordinate2D)coordinate;

@end

ParkingRegionOverlay.m

#import "ParkingRegionOverlay.h"


@implementation ParkingRegionOverlay

//@synthesize origin;
@synthesize polygon;

//@synthesize rect;


-(ParkingRegionOverlay*) initialize {
    MKMapPoint points[3] = {{38.53607,-121.765793}, {38.537606,-121.768379}, {38.53487,-121.770578}};
    polygon = [MKPolygon polygonWithPoints:points count:3];
    polygon.title = @"Some Polygon";
    return self;
}

- (MKMapRect)boundingMapRect{
    MKMapRect bounds = MKMapRectMake(-121.770578,38.537606,-121.770578-(-121.765793),38.537606-38.53487);
    return bounds;
}

- (CLLocationCoordinate2D)coordinate{
    return CLLocationCoordinate2DMake((38.537606-38.53487)/2, (-121.770578-(-121.765793))/2);
}

@end

你看到我放在viewForOverlay方法里的NSLog吗?它从未出现在控制台中,因此该函数从未被调用。有什么想法是怎么回事吗?非常感谢!

3个回答

10
主要问题在于代码提供了地图视图的纬度/经度坐标,而它期望的是MKMapPoints。有关差异的说明,请参见“理解地图几何”部分,该部分位于“位置感知编程指南”中。请点击此处。使用MKMapPointForCoordinate函数将纬度/经度坐标转换为MKMapPoint。
第二个问题是,在viewForOverlay中,它检查覆盖层是否为MKPolygon类型。你的覆盖层类ParkingRegionOverlay包含一个MKPolygon对象,但本身不是MKPolygon类型。
要解决主要问题,您需要更改initialize和boundingMapRect方法:
-(id)init {
    if (self = [super init]) {
        MKMapPoint points[3];
        CLLocationCoordinate2D c1 = {38.53607,-121.765793};
        points[0] = MKMapPointForCoordinate(c1);
        CLLocationCoordinate2D c2 = {38.537606,-121.768379};
        points[1] = MKMapPointForCoordinate(c2);
        CLLocationCoordinate2D c3 = {38.53487,-121.770578};
        points[2] = MKMapPointForCoordinate(c3);

        polygon = [MKPolygon polygonWithPoints:points count:3];
        polygon.title = @"Some Polygon";
    }
    return self;
}

- (MKMapRect)boundingMapRect{
    CLLocationCoordinate2D corner1 = 
        CLLocationCoordinate2DMake(38.537606, -121.770578);
    MKMapPoint mp1 = MKMapPointForCoordinate(corner1);

    CLLocationCoordinate2D corner2 = 
        CLLocationCoordinate2DMake(38.53487, -121.765793);
    MKMapPoint mp2 = MKMapPointForCoordinate(corner2);

    MKMapRect bounds = 
        MKMapRectMake(mp1.x, mp1.y, (mp2.x-mp1.x), (mp2.y-mp1.y));

    return bounds;
}

请注意,我将方法“initialize”更改为“init”。虽然这并没有阻止多边形的显示,但是您使用名为“initialize”的方法覆盖ParkingRegionOverlay的初始化方式,并且没有调用[super init],这不符合惯例。(同时从.h文件中删除“initialize”)
要解决第二个问题,viewForOverlay方法应该像这样:
- (MKOverlayView *)mapView:(MKMapView *)mapView 
    viewForOverlay:(id <MKOverlay>)overlay
{
    NSLog(@"in viewForOverlay!");

    if ([overlay isKindOfClass:[ParkingRegionOverlay class]])
                              //^^^^^^^^^^^^^^^^^^^^
    {
        //get the MKPolygon inside the ParkingRegionOverlay...
        MKPolygon *proPolygon = ((ParkingRegionOverlay*)overlay).polygon;

        MKPolygonView *aView = [[[MKPolygonView alloc] 
            initWithPolygon:proPolygon] autorelease];
                          //^^^^^^^^^^

        aView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
        aView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        aView.lineWidth = 3;

        return aView;
    }
    return nil;
}

最后,在viewDidLoad中更改代码:
ParkingRegionOverlay *polygon = [[ParkingRegionOverlay alloc] init];
[mapView addOverlay:polygon];
[polygon release]; //don't forget this

我忘了解释为什么即使设置了地图视图代理(无论如何都需要设置),viewDidOverlay仍未被调用。只有当叠加层的boundingMapRect在当前区域中可见时,才会调用viewDidOverlay方法。由于您的叠加层返回的是一个基本上没有意义的矩形,所以它不被认为是“可见的”,因此viewDidOverlay未被调用。 - user467105
兄弟,你真的很懂行啊。太厉害了...谢谢你!你不知道我已经试了多久才让它正常工作。哦,顺便问一下,如果我想在叠加层被点击时弹出一个调用弹窗,该怎么做呢?不需要详细的解释,但如果你能指点我一个方法或文档就太好了。非常感谢! - Stunner
1
很不幸,覆盖视图没有内置的MKAnnotationView那样的标注,因此需要更多的工作。您可以使用UIGestureRecognizer来检测触摸(请参见此答案)。使用单击、双击、长按——任何适合您的方式。但是,双击会与缩放冲突。在该答案中,在handleGesture方法中,您可以使用MKMapRectContainsPoint检查触摸点是否在覆盖层的boundingMapRect中,然后弹出一个视图。 - user467105
另一个简单的选择是在覆盖层的中心添加一个常规的MKPointAnnotation(即执行addOverlay和addAnnotation)。这可能看起来不太好,但很多工作已经为您处理了。 - user467105
关于MKMapPoints和纬度/经度坐标之间的区别,你提出了一个很好的观点。对我帮助很大。 - Kongress

0

在我看来,你似乎忘记设置代理了,应该像这样:

_mapView.delegate = self;


不错的想法,但是我通过IB设置了它,mapView连接到ParkingMapViewController,所以它确实是mapView的代理。我还在地图上有注释,它们可以正确显示和运行,如果我没有指定ParkingMapViewController作为地图视图的代理,这种情况是不可能的。 - Stunner
我建议您在编程中设置委托,而不是在IB中设置。 - justicepenny
以编程方式设置,但仍然没有成功。 :( - Stunner

0
你设置了这个吗?
yourMap.delegate=self;

你的目标是什么?3.x 还是 4.x?我认为 MKPolygon 是从 4.0 开始可用的。你可以尝试在前缀文件中添加导入语句,例如:
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#endif

目标是4.1版本。我已经按照您在viewDidLoad方法中指定的方式设置了委托,但没有成功。我还尝试了您的导入语句的版本,但仍然不起作用。有其他的想法吗? - Stunner
尝试将您的MKMapView变量设置为“IBOutlet MKMapView mapView;”。 - Mat
我已经在@property声明中这样做了,我确信那不会有任何作用。尽管如此,我还是试了一下,但没有起作用。 - Stunner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接