Adding custom AnnotationView in iphone - iphone

I am using following code to make custom AnnotationView.
My CustomPointAnnotation is a subclass of MKPointAnnotation with a setter/getter of Player
-(void) showMarkers
{
[self.mapView removeAnnotations:[self.mapView annotations]];
for (int i = 0 ; i < [self.playersArray count]; i ++)
{
Players *player = [self.playersArray objectAtIndex:i];
CustomPointAnnotation *annotationPoint = [[CustomPointAnnotation alloc] init];
[annotationPoint setPlayer:player];
if ([player.name isEqualToString:self.name.text])
{
NSLog(#"%# , %#" , player.name,self.name.text);
annotationPoint.coordinate = CLLocationCoordinate2DMake([player.latitude doubleValue]+.1, [player.longitude doubleValue]+.1);
[self.mapView addAnnotation:annotationPoint];
}
else
{
NSLog(#"%# , %#" , player.name,self.name.text);
annotationPoint.coordinate = CLLocationCoordinate2DMake([player.latitude doubleValue], [player.longitude doubleValue]);
[self.mapView addAnnotation:annotationPoint];
}
}
[self.mapView setUserInteractionEnabled:YES];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
// self.mapView.centerCoordinate = userLocation.location.coordinate;
myLocation = userLocation;
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([[annotation title] isEqualToString:#"Current Location"] )
{
return nil;
}
CustomAnnotationView *annView = [[CustomAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"players"];
CustomPointAnnotation *ptAnnotation = (CustomPointAnnotation *) annotation;
[annView setPlayer:ptAnnotation.player];
annView.image = [UIImage imageNamed:#"marker.png"];
annView.enabled = YES;
[annView setUserInteractionEnabled:YES];
return annView;
}
The problem comes at [annView setPlayer:ptAnnotation.player]; Unrecognized selector sent to instance
I am adding CustomPointAnnotation so it should convert it back. How can i solve this issue

OK, Im not sure how you declared the custom class, but it goes like this:
.h:
#interface CustomPointAnnotation: NSObject <MKAnnotation> {
}
#property (nonatomic) CLLocationCoordinate coordinate;
// Other properties like title, subtitle, etc.
.m
#implementation CustomPointAnnotation
#synthesize coordinate; // and other properties

#interface CustomPointAnnotation : NSObject <MKAnnotation&gt
{
Player *player;
}
#property(nonatomic,retain) Player *player;
#property (nonatomic) CLLocationCoordinate coordinate;
Do not subclass MKAnnotation istead confirm to MKAnnotation protocal.
#interface CustomAnnotationView : MKAnnotationView
{
}
no need to set the player. when you need to access the player object access it using the annotation in CustomAnnotationView.
CustomPointAnnotation *annotation=self.annotation;
annotation.player;

Related

My Custom MKAnnotationView isn't clickable

i'm working on a custom annotationview that show a image of background, with inside a custom image.
I've based my code from this: Custom MKAnnotationView with frame,icon and image
And my actually code is:
else if ([annotation isKindOfClass:[ImagePin class]]){
static NSString *identifierImage = #"ImagePinLocation";
MKAnnotationView *annotationImageView = (MKAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifierImage];
if(annotationImageView){
return annotationImageView;
}
else {
annotationImageView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifierImage];
annotationImageView.canShowCallout = YES;
annotationImageView.image = [UIImage imageNamed:#"image_bg_mappa"];
UIImage *frame = [UIImage imageNamed:#"image_bg_mappa"];
ImagePin *imagePinImage = annotation;
NSLog(#"%#", [NSString stringWithFormat:#"%#", imagePinImage.image]);
NSString *urlStringForImage = [NSString stringWithFormat:#"%#", imagePinImage.image];
NSURL *urlForImage = [NSURL URLWithString:urlStringForImage];
UIImageView *imageView = [[UIImageView alloc] init];
[imageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#", urlForImage]] placeholderImage:[UIImage imageNamed:#"avatar-placeholder.png"]];
UIGraphicsBeginImageContext(CGSizeMake(annotationImageView.image.size.width, annotationImageView.image.size.height));
[frame drawInRect:CGRectMake(0, 0, frame.size.width, frame.size.height)];
[imageView.image drawInRect:CGRectMake(2, 2, 48, 38)]; // the frame your inner image
annotationImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self action:#selector(writeSomething:) forControlEvents:UIControlEventTouchUpInside];
[rightButton setTitle:#"" forState:UIControlStateNormal];
annotationImageView.canShowCallout = YES;
annotationImageView.rightCalloutAccessoryView = rightButton;
annotationImageView.enabled = YES;
return annotationImageView;
}
}
And then i have two method:
(void)writeSomething {
}
(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
}
But:
Not show my rightButton callout(not show also the button)
I prefer that when i click on the full image/annotation it call mapView annotationView method.
How i can do it ? Why when i click on annotation, it not call my calloutAccessoryControlTapped method ?
In this map i have also more different type of pin(mkpinannotation), and works fine(also the method calloutAccessoryControlTapped works fine with these pins).
Where is the problem ?
Thanks to all, and sorry for my bad english(I'm learning it).
EDIT: My full code for viewForAnnotation method: https://gist.github.com/anonymous/6224519e308d6bf56c4c
The MKPinAnnotation works fine.
EDIT:
This is my ImagePin.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface ImagePin : NSObject <MKAnnotation>
- (id)initWithImage:(NSString*)image imagebeachId:(NSString*)imagebeachId coordinate:(CLLocationCoordinate2D)coordinate;
//- (MKMapItem*)mapItem;
#property (nonatomic, copy) NSString *imagebeachId;
#property (nonatomic, copy) NSString *image;
#property (nonatomic, assign) CLLocationCoordinate2D theCoordinate;
#end
And my ImagePin.m
#import "ImagePin.h"
#import <AddressBook/AddressBook.h>
#interface ImagePin ()
#end
#implementation ImagePin
#synthesize image = _image;
#synthesize imagebeachId = _imagebeachId;
#synthesize theCoordinate = _theCoordinate;
- (id)initWithImage:(NSString*)image imagebeachId:(NSString*)imagebeachId coordinate:(CLLocationCoordinate2D)coordinate {
if ((self = [super init])) {
//self.address = address;
self.image = image;
self.imagebeachId = imagebeachId;
self.theCoordinate = coordinate;
}
return self;
}
- (NSString *)title {
return #"";
}
- (NSString *)subtitle {
return _image;
}
- (CLLocationCoordinate2D)coordinate {
return _theCoordinate;
}
#end
EDIT:
This is where i add annotation:
- (void)imagePositions:(NSDictionary *)responseData {
for (id<MKAnnotation> annotation in self.mapView.annotations) {
if ([annotation isKindOfClass:[ImagePin class]]){
//[self.mapView removeAnnotation:annotation];
}
}
for (NSArray *row in responseData) {
NSString * imageBeachId = [row valueForKey:#"id"];
NSNumber * latitude = [row valueForKey:#"lat"];
NSNumber * longitude = [row valueForKey:#"lng"];
NSString * imageBeach = [row valueForKey:#"fb_photo_url"];
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude.doubleValue;
coordinate.longitude = longitude.doubleValue;
ImagePin *annotation = [[ImagePin alloc] initWithImage:imageBeach imagebeachId:imageBeachId coordinate:coordinate];
[self.mapView addAnnotation:annotation];
}
}
I have fixed all!
The problem is that title can't be empty(i was using #""... with a #"AAA works fine) and then for not show the callout i have done:
annotationView.canShowCallout = NO;
and implemented:
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
//here you action
}
A BIG thanks to Anna(the solution is your)!
First checkout that you give the delegate to MapView or not , if not then give the delegate like bellow..
yourMapView.delegate = self;
Also in .h file define that delegate like bellow..
#interface ViewController : UIViewController<MKMapViewDelegate,MKAnnotation>{...
after check that this bellow method called when accessory tapped...
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#"Do something ");
}
UPDATE:
Instead of Custom Button try to use it...
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
NSLog(#"viewForAnnotation...");
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[ImagePin class]]) {
MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil)
{
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier] autorelease];
}
if (annotation == mapView.userLocation)
return nil;
annotationView.image = [UIImage imageNamed:#"yourImageName.png"];
annotationView.annotation = annotation;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.rightCalloutAccessoryView.tag = 101;
annotationView.canShowCallout = YES;
// annotationView.animatesDrop = YES;
return annotationView;
}
return nil;
}
For anyone else that stumbles upon this post while implementing a custom MKAnnotationView, the problem may also be that you have to explicitly set the frame of your view.
MKMapView MKPointAnnotation tap event not called

Controls in a ViewController losing their state after memory warning while off screen

The situation is very similar to that described by this my other question, except that the delegation seems to work fine. I'm providing some more detail about my code. I'm just striping out non-relevant/trivial parts.
ReportScreen.h
#interface ReportScreen : UIViewController <UIImagePickerControllerDelegate, UITextViewDelegate, MBProgressHUDDelegate, SoapDelegate, MapLocationChoiceDelegate>
// ...
#property (nonatomic, retain) MKPointAnnotation *annotation;
#property (nonatomic, retain) IBOutlet UITextView *textView;
#property (nonatomic, retain) IBOutlet UIButton *cameraButton;
#property (nonatomic, retain) IBOutlet UIButton *libraryButton;
#property (nonatomic, retain) IBOutlet UIButton *locationButton;
#property (nonatomic, retain) IBOutlet UIButton *sendButton;
#end
ReportScreen.m
#implementation ReportScreen
#synthesize annotation;
#synthesize textView;
#synthesize cameraButton;
#synthesize libraryButton;
#synthesize locationButton;
#synthesize sendButton;
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Here I used to store the VC's state to a file but it shouldn't be needed now that I'm assigning it as delegate and said delegate seems to still be there even after a memory warning.
}
- (void)viewDidLoad {
[super viewDidLoad];
placeholderText = #"Tell us what's wrong…";
textView.text = placeholderText;
self.annotation = nil;
[self isReadyToSubmit];
hud = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:hud];
hud.delegate = self;
hud.labelText = #"Invio in corso…";
hud.dimBackground = YES;
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Here I used to restore the state of the VC from file but… y'know.
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self isReadyToSubmit];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"goToMap"]) {
MapScreen *vc = (MapScreen *)segue.destinationViewController;
// HERE's the magic
vc.mapLocationChoiceDelegate = self;
// MAGIC ends
if(self.annotation != nil) {
vc.annotations = [[NSMutableArray alloc] init];
[vc.annotations addObject:self.annotation];
}
}
}
- (BOOL)isReadyToSubmit {
if(self.annotation != nil) {
locationButton.highlighted = YES;
}
if(![textView.text isEqualToString:placeholderText] && self.annotation != nil) {
[sendButton setEnabled:YES];
} else {
[sendButton setEnabled:NO];
}
return [sendButton isEnabled];
}
- (void)textViewDidBeginEditing:(UITextView *)theTextView {
if([theTextView.text isEqualToString:placeholderText]) {
theTextView.text = #"";
}
UIBarButtonItem *done = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(didFinishEditing:)];
[self.navigationItem setRightBarButtonItem:done animated:YES];
}
- (void)textViewDidEndEditing:(UITextView *)theTextView {
if([theTextView.text isEqualToString:#""]) {
theTextView.text = placeholderText;
}
[self isReadyToSubmit];
}
- (void)didFinishEditing:(id)sender {
[self.navigationItem setRightBarButtonItem:nil animated:YES];
[self.textView resignFirstResponder];
}
// THIS is my delegate protocol's method
- (void)locationChosen:(MKPointAnnotation *)theAnnotation {
self.annotation = theAnnotation;
NSLog(#"R: %#", textView.text);
}
#end
MapScreen.h
#protocol MapLocationChoiceDelegate <NSObject>
- (void)locationChosen:(MKPointAnnotation *)annotation;
#end
// ---
#interface MapScreen : UIViewController <MKMapViewDelegate>
- (void)handleLongPress:(id)sender;
#property (nonatomic, retain) NSMutableArray *annotations;
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property (weak) id<MapLocationChoiceDelegate> mapLocationChoiceDelegate;
#end
MapScreen.m
#implementation MapScreen
#synthesize annotations;
#synthesize mapView;
#synthesize mapLocationChoiceDelegate;
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidLoad {
[super viewDidLoad];
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
lpgr.minimumPressDuration = 1.0;
[self.mapView addGestureRecognizer:lpgr];
[mapView addAnnotations:self.annotations];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
#pragma mark - Map handling
- (void)handleLongPress:(id)sender {
if(![sender isKindOfClass:[UILongPressGestureRecognizer class]]) {
return;
}
UILongPressGestureRecognizer *gr = (UILongPressGestureRecognizer *)sender;
if (gr.state != UIGestureRecognizerStateBegan) {
return;
}
CGPoint touchPoint = [gr locationInView:self.mapView];
CLLocationCoordinate2D touchMapCoordinate = [self.mapView convertPoint:touchPoint toCoordinateFromView:self.mapView];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = touchMapCoordinate;
self.annotations = [NSMutableArray arrayWithArray:[mapView annotations]];
for(id a in self.annotations) {
if(![a isKindOfClass:[MKUserLocation class]]) {
[mapView removeAnnotation:a];
}
}
[mapView addAnnotation:annotation];
self.annotations = [NSMutableArray arrayWithArray:[mapView annotations]];
// NSDictionary *userInfo = [NSDictionary dictionaryWithObject:annotation forKey:#"annotation"];
// [[NSNotificationCenter defaultCenter] postNotificationName:#"PositionChosen" object:nil userInfo:userInfo];
[self.mapLocationChoiceDelegate locationChosen:annotation];
NSLog(#"M: %#", ((ReportScreen *)self.mapLocationChoiceDelegate).textView.text);
}
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation {
if([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
static NSString *AnnotationIdentifier = #"Annotation";
MKPinAnnotationView* pinView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
} else {
pinView.annotation = annotation;
}
return pinView;
}
#end
The issue is:
ReportScreen pushes (performs segue to, actually) the MapScreen.
If I have some data in the UITextView or if I set some state to the buttons in the ReportScreen and I get a memory warning while the MapScreen is pushed, once I go back to the ReportScreen, all those fields don't show those settings. Apparently textView.text is still set, and so are the states of the buttons, they're just not shown.
Question: why?

rightCalloutAccessoryView on MKMapView not show

I have little problem with my iphone application. I have such classes and interfaces:
CinemaMapAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface CinemaMapAnnotation : NSObject <MKAnnotation>{
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString* title;
#property (nonatomic, copy) NSString* subtitle;
-(id)initWithCoordinate:(CLLocationCoordinate2D) c;
#end
CinemaMapAnnotation.m
#import "CinemaMapAnnotation.h"
#implementation CinemaMapAnnotation
#synthesize title, subtitle, coordinate;
-(id)initWithCoordinate:(CLLocationCoordinate2D) c{
self = [super init];
if (self) {
coordinate = c;
}
return self;
}
-(void) dealloc {
self.title = nil;
self.subtitle = nil;
[super dealloc];
}
#end
CinemasMapController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "Cinema.h"
#import "CinemaMapAnnotation.h"
#import "PopcornuaAppDelegate.h"
#interface CinemasMapController : UIViewController <MKMapViewDelegate, MKReverseGeocoderDelegate> {
MKMapView *mapView;
MKReverseGeocoder *reverseGeokoder;
}
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property (nonatomic, retain) IBOutlet MKReverseGeocoder *reverseGeokoder;
#end
CinemasMapController.m
#import "CinemasMapController.h"
#implementation CinemasMapController
#synthesize mapView, reverseGeokoder;
...
#pragma mark - Map Anotation
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id)annotation
{
static NSString* MyIdentifier = #"CinemaMapAnotation";
MKPinAnnotationView* pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:MyIdentifier];
if (!pinView)
{
MKPinAnnotationView* pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:MyIdentifier] autorelease];
pinView.draggable = NO;
pinView.animatesDrop = NO;
pinView.enabled = YES;
} else {
pinView.annotation = annotation;
}
if(annotation != mapView.userLocation){
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
// Add a detail disclosure button to the callout.
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinView.userInteractionEnabled = YES;
} else {
pinView.pinColor = MKPinAnnotationColorGreen;
}
return pinView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
NSLog(#"Not show button, so not work");
}
...
#end
My problem is, what all show and work, except not show rightCalloutAccessoryView button. mapView connected and have delegete to CinemasMapController on iphone view (also I try [mapView setDelegate:self]). So what I do wrong?
P.S. Code with line
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
execute - checked by NSLog.
Here how its look like - no button:
In viewForAnnotation, in the if (!pinView) block, a new local pinView variable is being declared instead of getting assigned to the outer variable.
As a result, the outer pinView variable never gets set (stays nil) and so the map view creates the default annotation view which is what you see.

custom MKAnnotation class for changing leftCalloutAnnotationView

I have created a custom class for the MKAnnotation
#interface NeighborMapAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString * title;
NSString * subtitle;
UIImageView * lcav;
}
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSString * subtitle;
#property (nonatomic, retain) UIImageView * lcav;
#end
NeighborMapAnnotation *neighbor = [[NeighborMapAnnotation alloc] initWithCoordinate:aCoordinate];
//imgView is some UIImageView that I already have
neighbor.leftCalloutAccessoryView = imgView;
- (MKAnnotationView *) mapView:(MKMapView *) mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
MKPinAnnotationView * annView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"custom view"] autorelease];
annView.animatesDrop = YES;
annView.canShowCallout = YES;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annView.rightCalloutAccessoryView = rightButton;
annView.leftCalloutAccessoryView = [annotation lcav];//is this right?
return annView;
}
I want to be able to change the leftCalloutAccessoryView of the annotation to an image. What code should I change in my custom MKAnnotation class?
The leftCalloutAccessoryView property is a property of the MKAnnotationView class (not in the MKAnnotation protocol).
In the viewForAnnotation delegate method of MKMapView, you provide an MKAnnotationView for your annotations. In that method, check if the annotation type is your custom annotation type using isKindOfClass and set the view's properties as needed.
In your NeighborMapAnnotation class, you could store the imageView as a UIImageView property and set that when creating the annotation.
In viewForAnnotation, you would set the view's leftCalloutAccessoryView to the annotation's imageView.
Edit:
Here's one way to implement it...
Add an image property to your custom annotation class:
#interface NeighborMapAnnotation : NSObject <MKAnnotation> {
...
UIImage *image;
}
...
#property (nonatomic, retain) UIImage *image;
#end
At the place where you create your annotations, set the image property:
NeighborMapAnnotation *neighbor = [[NeighborMapAnnotation alloc] initWithCoordinate:aCoordinate];
neighbor.image = [UIImage imageNamed:#"someimage.png"];
//the image could be different for each annotation
...
In the viewForAnnotation delegate method (make sure map view's delegate is set):
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[NeighborMapAnnotation class]])
{
static NSString *AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView)
{
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
}
else
{
pinView.annotation = annotation;
}
UIImageView *leftCalloutView = [[UIImageView alloc]
initWithImage:((NeighborMapAnnotation *)annotation).image];
pinView.leftCalloutAccessoryView = leftCalloutView;
[leftCalloutView release];
return pinView;
}
return nil;
}
thats great! i tried to extend my custom annotation class by few properties. but i had no access inside of viewForAnnotation delegate. what i´ve missed and learned here is that i have to cast the additional property on my custom annotation class. now it works! thank you! :-)

Problems Adding MKPolygon as an Overlay to an MKMapView

Ey there, so as the title says, I am having a tough time adding an MKPolygon as an overlay to an MKMapView. Here is the relevant code:
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
You see that NSLog I stuck in the viewForOverlay: method? Well that never shows up in the console, so that function is never called. Any idea of what's wrong? Many thanks!
The main issue is that the code is giving the map view latitude/longitude coordinates where it expects MKMapPoints. For an explanation of the difference, see "Understanding Map Geometry" in the Location Awareness Programming Guide. Use the MKMapPointForCoordinate function to convert from lat/long coordinates to an MKMapPoint.
The second issue is that in viewForOverlay, it is checking if overlay is of type MKPolygon. Your overlay class ParkingRegionOverlay contains an MKPolygon object inside it but is not itself of type MKPolygon.
To fix the main issue, you need to change the initialize and boundingMapRect methods:
-(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;
}
Please notice by the way that I changed the method "initialize" to "init". Though it wasn't preventing the polygon from showing, the way you are overriding the initialization of ParkingRegionOverlay using a method called "initialize" and not calling [super init] does not follow convention. (Also remove "initialize" from the .h file.)
To fix the second issue, the viewForOverlay method should look like this:
- (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;
}
Finally, change the code in viewDidLoad:
ParkingRegionOverlay *polygon = [[ParkingRegionOverlay alloc] init];
[mapView addOverlay:polygon];
[polygon release]; //don't forget this
it seems to me that you forget to set your delegate
somthing like that
_mapView.delegate = self;
Have you set this?:
yourMap.delegate=self;
And what's your target? 3.x or 4.x?? I think MKPolygon is available from 4.0.
You can try to add the import clause to your prefix file like:
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#endif