Проблемы с добавлением MKPolygon в качестве наложения в MKMapView

Эй, как следует из названия, мне трудно добавить MKPolygon в качестве наложения на MKMapView. Вот соответствующий код:
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

Вы видите, что NSLog я застрял в методе viewForOverlay:? Ну, это никогда не отображается в консоли, поэтому эта функция никогда не вызывается. Есть идеи, что не так? Большое спасибо!


person Stunner    schedule 03.12.2010    source источник


Ответы (3)


Основная проблема заключается в том, что код дает координаты широты/долготы представления карты, где он ожидает 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;
}

Обратите внимание, кстати, что я изменил метод «инициализация» на «инициализация». Хотя это не мешало отображению многоугольника, способ, которым вы переопределяете инициализацию ParkingRegionOverlay, используя метод «initialize» и не вызывая [super init], не соответствует соглашению. (Также удалите «инициализировать» из файла .h.)

Чтобы исправить вторую проблему, метод 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
person Community    schedule 03.12.2010
comment
Я забыл объяснить, почему viewDidOverlay не вызывался, даже если был установлен делегат представления карты (который должен быть независимо). Метод viewDidOverlay вызывается только в том случае, если ограничивающий MapRect наложения будет виден в текущей области. Поскольку ваш оверлей возвращал по существу бессмысленный прямоугольник, он не считался видимым, и viewDidOverlay не вызывался. - person ; 03.12.2010
comment
Чёрт возьми, ты действительно знаешь своё дело. Удивительно... Спасибо, чувак! Вы не представляете, как долго я пытался заставить это работать. Да, и пока я в теме, как мне сделать так, чтобы выноска выскакивала из оверлея при нажатии? Нет необходимости в длинных объяснениях, но если бы вы могли указать мне метод или документ, это было бы здорово. Большое спасибо! - person Stunner; 03.12.2010
comment
К сожалению, в оверлейном представлении нет встроенной выноски, такой как MKAnnotationView, поэтому требуется дополнительная работа. Вы можете использовать UIGestureRecognizer для обнаружения прикосновения (см. этот ответ) . Используйте одинарное нажатие, двойное нажатие, длительное нажатие — все, что вам подходит. Однако двойное нажатие будет конфликтовать с масштабированием. В этом ответе в методе handleGesture вы можете проверить, находится ли точка касания в boundingMapRect наложения, используя MKMapRectContainsPoint, а затем открыть представление. - person ; 03.12.2010
comment
Другой простой вариант — просто добавить обычную аннотацию MKPointAnnotation в центр наложения (т. е. сделать addOverlay и addAnnotation). Это может выглядеть не очень хорошо, но за вас позаботятся о большом количестве работы. - person ; 03.12.2010
comment
Отличное замечание о различии между MKMapPoints и координатами широты и долготы. Мне очень помог. - person Kongress; 09.06.2011

мне кажется, что вы забыли установить своего делегата что-то вроде этого

_mapView.delegate = сам;

person justicepenny    schedule 03.12.2010
comment
Хорошая мысль, но нет, я настроил его через IB, и mapView подключен к ParkingMapViewController, так что он действительно является делегатом mapView. У меня также есть аннотации на карте, которые отображаются и функционируют должным образом, чего не было бы, если бы я не указал ParkingMapViewController в качестве делегата представления карты. - person Stunner; 03.12.2010
comment
я бы предложил установить делегата программно, а не в IB. - person justicepenny; 03.12.2010
comment
Настроил программно, но все равно безрезультатно. :( - person Stunner; 03.12.2010

Вы установили это?:

yourMap.delegate=self;

И какова ваша цель? 3.х или 4.х?? Я думаю, что MKPolygon доступен с версии 4.0. Вы можете попробовать добавить предложение импорта в свой файл префикса, например:

#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#endif
person Mat    schedule 03.12.2010
comment
Цель 4.1. И я попытался установить своего делегата так, как вы указали в методе viewDidLoad, но безрезультатно. Я также попробовал вашу версию пункта импорта, но безуспешно. Любые другие идеи? - person Stunner; 03.12.2010
comment
попробуйте установить переменную MKMapView как «IBOutlet MKMapView mapView;» - person Mat; 03.12.2010
comment
У меня это уже есть в объявлении @property, и я уверен, что ничего не получится. Тем не менее, я попробовал, и это не сработало. - person Stunner; 03.12.2010