0

に注釈を追加しようとしていますMKMapView

プロトコルCustomMapPinに準拠したクラスを作成しましたMKAnnotation

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

@interface CustomMapPin : NSObject <MKAnnotation> {

    CLLocationCoordinate2D coordinate;
    NSString *title;
    NSString *subtitle;
}

@property(nonatomic, assign) CLLocationCoordinate2D coordinate;
@property(nonatomic, copy) NSString *title;
@property(nonatomic, copy) NSString *subtitle;
@property(nonatomic, strong) NSString *type; // this is to differentiate between the different annotations on the map

@end

CustomMapAnnotationViewのサブクラスであるクラスを作成しましたMKAnnotationView

CustomMapAnnotationView.h

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

@interface CustomMapAnnotationView : MKAnnotationView
@property (nonatomic, strong) UIImageView *annotationImage;
@end

CustomMapAnnotationView.m

#import "CustomMapAnnotationView.h"

@implementation CustomMapAnnotationView

-(id) initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];

    if (self) {
        self.frame = CGRectMake(0, 0, 28, 40);
        self.backgroundColor = [UIColor clearColor];

        self.annotationImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 28, 40)];
        self.annotationImage.contentMode = UIViewContentModeScaleAspectFit;
        [self addSubview:self.annotationImage];

    }
    return self;
}

@end

内部にカスタムピンを追加してFindMechanicViewControllerCLLocationManagerDelegateますMKMapViewDelegate

コード スニペットは次のとおりです。

-(void) viewWillAppear:(BOOL)animated {
    [self.locationManager startUpdatingLocation];
    self.currentLocation = [self.locationManager location];

    // Set the region of the map
    MKCoordinateSpan mapViewSpan = MKCoordinateSpanMake(0.01, 0.01);
    MKCoordinateRegion mapRegion = MKCoordinateRegionMake(self.currentLocation.coordinate, mapViewSpan);
    [self.mapView setRegion:mapRegion];

    // Add custom pin showing user location
    CustomMapPin *annotation = [[CustomMapPin alloc] init];
    annotation.title = @"Current Location";
    annotation.coordinate = self.currentLocation.coordinate;
    annotation.type = @"user location";
    [self.mapView addAnnotation:annotation];
}

そしてデリゲートメソッド

-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    static NSString *reuseId = @"CustomMapPin";
    CustomMapAnnotationView *annotationView = (CustomMapAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];

    if ([annotation isKindOfClass:[CustomMapPin class]]) {
        CustomMapPin *customAnnotation = (CustomMapPin *)annotation;

       if ([customAnnotation.type isEqualToString:@"user location"]) {
           [annotationView setAnnotation:customAnnotation];
           [annotationView setImage:[UIImage imageNamed:@"pin_user"]];
           [annotationView setCanShowCallout:YES];
        }

    }
    return annotationView;
}

これは地図上に何も表示されません。これを修正するにはどうすればよいですか?

4

1 に答える 1

5

ではviewForAnnotationCustomMapAnnotationView実際に割り当て+初期化されることはありdequeueReusableAnnotationViewWithIdentifierません ( はこれを行いません)。

viewForAnnotation呼び出されても返される必要がありますnil。つまり、マップ ビューはどこかに赤いピンを配置する必要があります (デリゲート メソッドが呼び出されない場合、マップ ビューはデフォルトで赤いピンになります)。注釈が追加されている座標をログに記録し、そこを確認します。

修正されたものは次のviewForAnnotationようになります。

-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    if ([annotation isKindOfClass:[CustomMapPin class]]) {
        static NSString *reuseId = @"CustomMapPin";

        CustomMapAnnotationView *annotationView = (CustomMapAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
        if (!annotationView) {
            annotationView = [[CustomMapAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
            [annotationView setCanShowCallout:YES];
        }

        CustomMapPin *customAnnotation = (CustomMapPin *)annotation;

        //view's annotation should be set regardless of "type"
        [annotationView setAnnotation:customAnnotation];

        if ([customAnnotation.type isEqualToString:@"user location"]) {
            [annotationView setImage:[UIImage imageNamed:@"pin_user"]];
        }
        else {
            //If it's not a "user location", then set image
            //to something else otherwise image will either be nil
            //or it will show some other annotation's image...
            [annotationView setImage:[UIImage imageNamed:@"pin_other"]];
        }

        return annotationView;
    }

    return nil;
}

コードに関するその他の問題:

  1. ではviewWillAppear、コードは を呼び出した直後に位置を取得していますstartUpdatingLocation。これは毎回動作することが保証されているわけではなく、「動作」したとしても、キャッシュされた古い場所を取得する可能性が高くなります。機能しない場合、注釈は 0,0 (大西洋) になるか、座標が無効なためにアプリがクラッシュします。didUpdateLocationsデリゲート メソッドで場所を読み取る方がはるかに優れています。でviewWillAppear呼び出しstartUpdatingLocation、次に でdidUpdateLocations、位置の精度と年齢が適切である場合は、呼び出しstopUpdatingLocationてからその位置を使用します (注釈を作成して追加するなど)。
  2. ではCustomMapAnnotationViewannotationImageオブジェクトが作成および追加されますが、そのimageプロパティは設定されません。annotationImage実際には、実際には何にも使用されません。
  3. CustomMapAnnotationViewあなたの目的にはクラス全体は不要です。ではviewForAnnotation、コードは(を使用する代わりに) でimageプロパティを設定しています。このプロパティは から継承されます。組み込みの基本クラスだけで、実行している作業に必要なすべてが得られます。すでにプロパティがあり、自動的に表示されます (独自の を作成する必要はありません)。CustomMapAnnotationViewannotationImageimageMKAnnotationViewMKAnnotationViewimageUIImageView
于 2015-02-24T21:37:49.507 に答える