My Custom MKAnnotationView isn't clickable - iphone

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

Related

How to show Image over Map not as Pin but as seperate image? [duplicate]

This question already has answers here:
MKMapView: Instead of Annotation Pin, a custom view
(3 answers)
Closed 9 years ago.
I want to show two flags on Map but these are not pins. I search a lot for this but could not find solutions but to add as pin.
please help
You are looking for Map Overlay MKOverlayView.
Check these tutorials:
Overlay View
Image Overlay
Creating overlay
Creating a MKOverlayView
Create a subclass of MKOverlayView like:
.h
#import
#import
#interface MapOverlayView : MKOverlayView
{
}
#end
.m
#import "MapOverlayView.h"
#implementation MapOverlayView
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)ctx
{
UIImage *image = [UIImage imageNamed:#"yourImage.png"];
CGImageRef imageReference = image.CGImage;
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
CGContextDrawImage(ctx, theRect, imageReference);
}
#end
Adding Overlay
Implement the viewForOverlay: ,inside that create the overlay and add to map.
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MapOverlay *mapOverlay = (MapOverlay *)overlay;
MapOverlayView *mapOverlayView = [[[MapOverlayView alloc] initWithOverlay:mapOverlay] autorelease];
return mapOverlayView;
}
you can do it with MKAnnotationView with image property like bellow in viewForAnnotation: method..
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"Current";
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.canShowCallout = YES;
return annotationView;
}
try this one
annotation = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"try"];
annotation.canShowCallout = YES;
annotation.image = [UIImage imageNamed:#"image.png"];
return annotation;
and do not use annotation.animatesDrop property.
If you are talkin about MKMapView:
To show an image instead of Pin annotation , you need to override MKMapView's method
- (MKAnnotationView *)viewForAnnotation:(id < MKAnnotation >)annotation
Like this:
- (MKAnnotationView *)viewForAnnotation:(id < MKAnnotation >)annotation{
static NSString* annotationIdentifier = #"Identifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if(annotationView)
return annotationView;
else
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
annotationView.canShowCallout = YES;
// here you need to give the image you want instead of pin
annotationView.image = [UIImage imageNamed:[NSString stringWithFormat:#"balloon.png"]];
return annotationView;
}
return nil;
}

My viewForAnnotation function is never called?

I have made these pieces of code for my custom annotation:
- (void)viewDidLoad
{
[super viewDidLoad];
mapView.delegate=self;
[self AddLocations];
[self initiateMap];
......
this is my addLocation function:
-(id<MKAnnotation>)addAnnotationWithTitle: (NSString*) title coordinate:(CLLocationCoordinate2D)
Location imageName:(NSString*) imageName{
CustomAnnotation *annotation = [[CustomAnnotation alloc]init];
annotation.title = title;
annotation.subtitle = #"This is a subtitle";
[annotation setCoordinate:Location];
annotation.imageName = imageName;
return annotation;
}
and my CustomAnnotation Class:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
NSLog(#"Test");
if([annotation isKindOfClass:[MKUserLocation class]]){
return nil;
}
if([annotation isKindOfClass:[CustomAnnotation class]]){
CustomAnnotation *customAnnotation = annotation;
static NSString* annotationid = #"Annotation";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:annotationid];
if(!annotationView){
annotationView = [[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:annotationid];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}else{
annotationView.annotation = annotation;
}
annotationView.image = [UIImage imageNamed:customAnnotation.imageName];
return annotationView;
}
return nil;
}
For some reason the viewForAnnotation function is never used. Can anyone help me out here?
Thanks

Adding custom AnnotationView in 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;

How to make the callout button in an annotation in MKMapKit go to another view controller

I want the button in the callout to go to another view controller to display extra information, and then be able to come back to the map view. the map is inside of a tabbed view controller. At the moment, if you click on the button in the callout, the app crashes and gives you a thread error. Not sure on what to do at the moment.
this is the header file:
#import UIKit/UIKit.h>
#import MapKit/MapKit.h>
#define METERS_PER_MILE 1609.344
#interface MSKSecondViewController :UIViewController<MKMapViewDelegate>
{
IBOutlet MKMapView *stillwellMapView;
}
#property (nonatomic, assign) CLLocationCoordinate2D mainEntranceToStillwellCoordinate;
#end
and this is the implementation file:
#interface MSKSecondViewController ()
#end
#implementation MSKSecondViewController
#synthesize mainEntranceToStillwellCoordinate;
- (void)viewDidLoad
{
[super viewDidLoad];
stillwellMapView.delegate=self;
// Do any additional setup after loading the view, typically from a nib.
[self mainEntrancetoStillwellCoordinate];
[self bambooForestCoordinate];
}
- (void)mainEntrancetoStillwellCoordinate
{
MKPointAnnotation * main = [[MKPointAnnotation alloc]init];
CLLocationCoordinate2D mainLocation;
mainLocation.latitude = 40.831685;
mainLocation.longitude = -73.477453;
[main setCoordinate:mainLocation];
[main setTitle:#"Entrance"];
[main setSubtitle:#"Main"];
[stillwellMapView addAnnotation:main];
}
- (void)bambooForestCoordinate
{
MKPointAnnotation * bambooForest = [[MKPointAnnotation alloc]init];
CLLocationCoordinate2D bambooForestLocation;
bambooForestLocation.latitude = 40.829118;
bambooForestLocation.longitude = -73.466443;
[bambooForest setCoordinate:bambooForestLocation];
[bambooForest setTitle:#"Bamboo Forest"];
[bambooForest setSubtitle:#"Exit to Woodbury"];
[stillwellMapView addAnnotation:bambooForest];
}
- (void)viewDidUnload
{
stillwellMapView = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:
(id<MKAnnotation>)annotation
{
MKPinAnnotationView * annView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
UIButton *entranceButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[entranceButton addTarget:self action:#selector(entranceButtonPressed:)
forControlEvents:UIControlEventTouchUpInside];
annView.rightCalloutAccessoryView = entranceButton;
entranceButton = [UIButton buttonWithType:UIButtonTypeCustom];
entranceButton.frame = CGRectMake(0, 0, 23, 23);
entranceButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
entranceButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
[UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annView.animatesDrop=TRUE;
annView.canShowCallout = YES;
annView.calloutOffset = CGPointMake(-5, 5);
return annView;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)viewWillAppear:(BOOL)animated
{
//the coordinates in which the map shows once loaded
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 40.831922;
zoomLocation.longitude= -73.476353;
//the amount of area shown by the map when it loads
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation,
0.15*METERS_PER_MILE, 0.15*METERS_PER_MILE);
MKCoordinateRegion adjustedRegion = [stillwellMapView regionThatFits:viewRegion];
[stillwellMapView setRegion:adjustedRegion animated:YES];
}
#end
Add the event which you have registered on Touch Up Inside with entranceButton.
-(void) entranceButtonPressed:(UIButton *)sender
{
//Write the controller push code here
}
Also, in the code you have reinitialize the entranceButton once it is assigned to rightCalloutAccessoryView.
In the mapView:viewForAnnotation: delegate method
-(MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation
// add the following line
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinView.rightCalloutAccessoryView = rightButton;
and then implement the code to navigate to other view controller in the following delegate method
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
Make sure view controller is embedded inside navigation controller

HOw to get index on click of particlular annotation pin in iphone

This is BridgeAnnotation interface which has delegate of MKAnnotation
#interface BridgeAnnotation : NSObject <MKAnnotation>
{
}
#property(nonatomic,retain) NSString *lat,*lon,*titlevalue,*subtitlevalue;
#property(nonatomic,assign) NSInteger myindex;
#end
I am setting value to myindex variable in my method like as below
BridgeAnnotation *bridgeAnnotation = [[BridgeAnnotation alloc] init];
[bridgeAnnotation setLat:[#"" stringByAppendingFormat:#"%f",theCoordinate.latitude]];
[bridgeAnnotation setLon:[#"" stringByAppendingFormat:#"%f",theCoordinate.longitude]];
[bridgeAnnotation setTitlevalue:[PMLObj ProductTitle]];
[bridgeAnnotation setSubtitlevalue:[[PMLObj ProductPrice] stringByAppendingFormat:#"$"]];
[bridgeAnnotation setMyindex:i];
[self.mapView addAnnotation:bridgeAnnotation];
THis is my overiding method
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString* BridgeAnnotationIdentifier = #"bridgeAnnotationIdentifier";
MKPinAnnotationView* pinView = (MKPinAnnotationView *)
[mapView dequeueReusableAnnotationViewWithIdentifier:BridgeAnnotationIdentifier];
if (!pinView)
{
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
NSLog(#"---%d",rightButton.tag);
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
In above method I want to access myindex of BridgeAnnotation class..
How it possible? OR I have to use other method for that??
Can any one help me?
If you want to capture the annotation on a click then you should use this delegate
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
BridgeAnnotation *annotation = (BridgeAnnotation *)mapView.annotation;
NSInteger *yourIndex = annotation.myindex;
}