Getting wrong annotation from MapView Delegate method - iphone

I have declared the following in my .h file:
Annotation *annoForMoreDetails.
However when I try to set it to the current annotation in the method
- (MKAnnotationView *)mapView:(MKMapView *)mapViews viewForAnnotation:(id <MKAnnotation> )annotation
It gets set to the wrong object.
Here is my code:
- (MKAnnotationView *)mapView:(MKMapView *)mapViews viewForAnnotation:(id <MKAnnotation> )annotation
{
NSLog(#"welcome into the map view annotation");
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
for (annotation in [mapView annotations]) {
if ([[mapView annotations] containsObject:annotation]) {
annoForMoreDetails = annotation;
}
}
if (annoForMoreDetails.coordinate.latitude != mapViews.userLocation.coordinate.latitude && annoForMoreDetails.coordinate.longitude != mapViews.userLocation.coordinate.longitude) {
// try to dequeue an existing pin view first
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.pinColor = MKPinAnnotationColorGreen;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[rightButton addTarget:self
action:#selector(moreDetails)
forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = rightButton;
return pinView;
}
else if (annoForMoreDetails.coordinate.latitude == mapViews.userLocation.coordinate.latitude && annoForMoreDetails.coordinate.longitude == mapViews.userLocation.coordinate.longitude) {
return nil;
}
return nil;
}
- (void)moreDetails {
annotationCalloutView.frame = CGRectMake(70, 120, 188, 218);
annotationCalloutView.alpha = 0.0;
mapView.userInteractionEnabled = NO;
annotationCalloutView.userInteractionEnabled = YES;
titleLabel.text = annoForMoreDetails.title;
titleLabel.numberOfLines = 0;
titleLabel.userInteractionEnabled = NO;
addressLabel.text = annoForMoreDetails.subtitle;
[self.view addSubview:annotationCalloutView];
[UIView beginAnimations:#"callout" context:NULL];
[UIView setAnimationDuration:0.6];
annotationCalloutView.alpha = 1.0;
[UIView commitAnimations];
}
If you see anything wrong please point it out!

Are you trying to use annoForMoreDetails to know which annotation the user tapped on so you can show more details? If that's the case, there's an easier way. Use the map view's calloutAccessoryControlTapped delegate method. It will be called when the user taps on the accessory button and it will pass the annotation view which includes the annotation as a property.
Remove the annoForMoreDetails instance variable and in viewForAnnotation, remove the for-loop that sets annoForMoreDetails (I think it ends up setting it to the last annotation every time). Remove all other references to annoForMoreDetails.
Also in viewForAnnotation, remove the addTarget line on the rightButton since you'll replace your custom moreDetails method with an implementation of calloutAccessoryControlTapped:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
Annotation *annoForMoreDetails = (Annotation *)view.annotation;
//the code currently in moreDetails method goes here...
}

Related

How Do I Determine Which MKAnnotation is clicked?

I'm a noob to iphone developoment and i am trying to determine the int value of an annotation so I can then take that int value and cross reference it to an array to get a corresponding value. However, when i try to get the int value with the .tag method the value always returns as zero. If I have 5 annontations I need to be able to determine which annontation is 0,1,2,3 and 4. Any help is greatly appreciated.
MY CODE
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
if (view.selected==YES) {
NSInteger annotationIndex = view.tag; //Always returns zero
NSLog(#"annotationIndex: %i", annotationIndex);
}
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
// Define your reuse identifier.
static NSString *identifier = #"MapPoint";
if ([annotation isKindOfClass:[MapPoint class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.animatesDrop = YES;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
NSInteger clickIndex = rightButton.tag; //Always returns zero, despite there being 5 annotations
NSLog(#"buttonIndex: %i", clickIndex);
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
annotationView.rightCalloutAccessoryView = rightButton;
return annotationView;
}
return nil;
}
The tag property is something you have to set. I think you're not setting it anywhere.
Certainly for the UIButton that you create using buttonWithType. The default tag value is 0, so you're always going to get 0 asking for the tag right after the view (Button) is created.
Write below code to get index value
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
// Annotation is your custom class that holds information about the annotation
if ([view.annotation isKindOfClass:[Annotation class]]) {
Annotation *annot = view.annotation;
NSInteger index = [self.arrayOfAnnotations indexOfObject:annot];
}
}
With my previous post https://stackoverflow.com/a/34742122/3840428

Pass data to detailView when annotation tapped on mapview

I have a map view and there are 10 store locations which data comes via webservice. I just want to push to my detail view to show address, telephone and other informations of the clicked store.
I need to pass data to my detailview when user tapped or touch up inside to a annotation on mapkit. There are 10 annotations in my mapview and first I want to know, how can I understand or how can I get the annotationID of which annotation is clicked?
this is the method I return pins
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]) return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* pinView = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.pinColor=MKPinAnnotationColorPurple;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = rightButton;
return pinView;
}
/* and my action method for clicked or tapped annotation: */
- (IBAction)showDetails:(id)sender{
NSLog(#"Annotation Click");
[[mtMap selectedAnnotations]objectAtIndex:0];
magazaDetayViewController *detail = [[magazaDetayViewController
alloc]initWithNibName:#"magazaDetayViewController" bundle:nil];
detail.sehir=#"";
detail.magazaAdi=#"";
detail.adres=#"";
detail.telefon=#"";
detail.fax=#"";
[self.navigationController pushViewController:detail animated:YES];
}
if i can just get the clicked annotation index no i can fill detail properties with my array.
if this is impossible is there any other way to do it?
First in your annotaion view delegat make a button to go in detail view like bellow:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"current"];
mypin.pinColor = MKPinAnnotationColorPurple;
mypin.backgroundColor = [UIColor clearColor];
UIButton *goToDetail = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mypin.rightCalloutAccessoryView = myBtn;
mypin.draggable = NO;
mypin.highlighted = YES;
mypin.animatesDrop = TRUE;
mypin.canShowCallout = YES;
return mypin;
}
Now use the following delegate whenever the button in annotationView will get tapped the following delegate will be called from where you can easly get which particular annotaion's button is tapped
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
annotation *annView = view.annotation;
detailedViewOfList *detailView = [[detailedViewOfList alloc]init];
detailView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
detailView.address = annView.address;
detailView.phoneNumber = annView.phonenumber;
[self presentModalViewController:detailView animated:YES];
}
here annotaion is a class importing MKAnnotaion.h and address and phonenumber are properties of annotaion class you can make many more while the address and phoneNumber properties of detailView class are strong. So that you can pass values. Hope this will help you!
Bellow is Delegate method of MapView......
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
}
when user tap annotation pin above method call automaticaly if method define in .m file nut first declare MKMapViewDelegate delegate in .h file
and also you can get title or subtitle and id from google place API....
link is...
https://developers.google.com/maps/documentation/places/
for(int i=0; i<[arrLat count];i++) {
CLLocationCoordinate2D theCoordinate1;
konumpin* myAnnotation1=[[konumpin alloc] init];
theCoordinate1.latitude = [[arrLong objectAtIndex:i] doubleValue];
theCoordinate1.longitude = [[arrLat objectAtIndex:i] doubleValue];
myAnnotation1.coordinate=theCoordinate1;
myAnnotation1.title=[arrMagaza objectAtIndex:i];
[annotations addObject:myAnnotation1];
}
[mtMap addAnnotations:annotations];

iOS- Get button on MKAnnotationView to delete pin

I have created a MKAnnotationView and do add a UIButton on it. Now I would like that button to remove the pin it is in.
This is how I add the button:
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *pinAnnotation = nil;
if(annotation != myMapView.userLocation)
{
NSString *defaultPinID = [[NSString alloc] initWithFormat:#"pin%d",pinCount];
pinAnnotation = (MKPinAnnotationView *)[myMapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinAnnotation == nil )
pinAnnotation = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinAnnotation.canShowCallout = YES;
//// ADDING MY BUTTON
UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinAnnotation.rightCalloutAccessoryView = deleteButton;
//// ADDING IT'S ACTION
[deleteButton addTarget:self action:#selector(deletePin) forControlEvents:UIControlEventTouchUpInside];
}
pinCount++;
return pinAnnotation;
}
As you can see there, I set the action to call this method:
-(void)deletePin
{
//What to put here...?
}
How can I make that action delete it's button's pin?
I figured maybe sending the id thru or something, but am not sure how.
With annotation callout accessory views, do not use your own target/action method.
Instead, use the map view's calloutAccessoryControlTapped delegate method which will make this job much easier.
Remove the addTarget line and your custom method. Then implement the delegate method instead:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
[mapView removeAnnotation:view.annotation];
}
Also, unrelated, but the way you are setting the re-use identifier is wrong and defeats re-usability by assigning a different id to every annotation. The following is recommended:
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *pinAnnotationView = nil;
if (annotation != myMapView.userLocation)
{
NSString *reuseId = #"StandardPin";
pinAnnotationView = (MKPinAnnotationView *)[myMapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if ( pinAnnotationView == nil )
{
pinAnnotationView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId] autorelease];
pinAnnotationView.canShowCallout = YES;
UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinAnnotationView.rightCalloutAccessoryView = deleteButton;
}
else
//update annotation property if view is being re-used...
pinAnnotationView.annotation = annotation;
}
return pinAnnotationView;
}
Get the sender in your callback
[deleteButton addTarget:self action:#selector(deletePin:) forControlEvents:UIControlEventTouchUpInside];
-(void)deletePin:(id)sender
{
//What to put here...?
}
Then get the MKAnnotation associated with the MKPinAnnotationView, remove it from the MKMapView's annotations and redraw ([mapView setNeedsDisplay])

detailButton unable to push information over. Pushed page always have empty labels

Hi can some1 plz help me....
The problem is this: Everything seems alright.. i am able to push to another page once i tap on the detailButton. However, the page which i am able to push to is always only a view without any values passed into the labels. All my labels in the view have nothing inside.. Am i doing something wrong or any wrong concept here?
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
BOOL isRed = NO;
//BOOL isPurple = YES;
if([annotation isKindOfClass:[MyAnnotation2 class]])
isRed = YES;
MKPinAnnotationView *pinView = nil;
if(isRed) {
static NSString *redPin = #"redPin";
pinView = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:redPin];
if (!pinView) {
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:redPin] autorelease];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.animatesDrop = YES;
pinView.canShowCallout = YES;
UIButton *detailButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinView.rightCalloutAccessoryView = detailButton;
}
else{
pinView.annotation = annotation;
}
}
else {
static NSString *greenPin = #"greenPin";
pinView = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:greenPin];
if (!pinView) {
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:greenPin] autorelease];
pinView.pinColor = MKPinAnnotationColorGreen;
pinView.animatesDrop = NO;
pinView.canShowCallout = YES;
UIButton *detailButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinView.rightCalloutAccessoryView = detailButton;
}
}
return pinView;
}
//
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#"calloutAccessoryControlTapped");
if (self.patientDetailsViewController == nil) {
self.patientDetailsViewController = [[[PatientDetailsViewController alloc] initWithNibName:#"PatientDetailsViewController" bundle:nil] autorelease];
}
MyAnnotation2 *selectedObject = (MyAnnotation2 *)view.annotation;
_patientDetailsViewController.nric = selectedObject.title;
NSLog(#"%#",_patientDetailsViewController.nric);
[self.navigationController pushViewController:_patientDetailsViewController animated:YES];
}
Don't use your own target/action and tagging for the callout accessory button.
Instead, use the MKMapViewDelegate method calloutAccessoryControlTapped:. Remove the addTarget line and implement the delegate method.
In that delegate method, you can access the annotation tapped using:
MyAnnotation2 *selectedObject = (MyAnnotation2 *)view.annotation;

MapView Annotation not dragging

I am trying to implement a draggable "pin" (actually a custom icon) in a map view. This is the delegate code that I have:
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
MKAnnotationView *aView;
aView=(MKAnnotationView *) [mvMap dequeueReusableAnnotationViewWithIdentifier:annotation.title];
if (aView==nil)
aView=[[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotation.title] autorelease];
else
aView.annotation=annotation;
[aView setImage:[UIImage imageNamed:selIcon]];
aView.canShowCallout=TRUE;
[aView setDraggable:YES];
return aView;
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
MKAnnotationView *aV;
for (aV in views) {
CGRect endFrame = aV.frame;
int xDelta=0;
xDelta=sIcons.selectedSegmentIndex*61+22;
aV.frame = CGRectMake(aV.frame.origin.x-145+xDelta, aV.frame.origin.y - 150.0, aV.frame.size.width, aV.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.7];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[aV setFrame:endFrame];
[UIView commitAnimations];
}
}
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState {
if (oldState == MKAnnotationViewDragStateDragging) {
addAnnotation *annotation = (addAnnotation *)view.annotation;
annotation.subtitle = [NSString stringWithFormat:#"%f %f", annotation.coordinate.latitude, annotation.coordinate.longitude];
}
if (newState == MKAnnotationViewDragStateEnding) {
CLLocationCoordinate2D droppedAt = view.annotation.coordinate;
NSLog(#"dropped at %f,%f", droppedAt.latitude, droppedAt.longitude);
}
}
The problem is that didChangeDragState is never being called (I've set a breakpoint in the routine to be sure). Everything else is working fine. My icons animate into the view, etc. When I tap the icon and hold my finger down the icon stays in place (the map doesn't move either which makes me think that I've actually hit the icon). Am I missing some kind of initialization?
Got it! The problem was in the interface file of my custom annotation class. The offending line read:
#property (nonatomic,readonly) CLLocationCoordinate2D coordinate;
It has to read:
#property (nonatomic,readwrite,assign) CLLocationCoordinate2D coordinate;
I guess that it has to have read/write capability.
Use MKPinAnnotationView instead of MKAnnotationView.
MKPinAnnotationView *pin = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"purple_pin"];
if (pin==nil)
{
pin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"purple_pin"];} else {
pin.annotation=annotation;
}
pin.pinColor = MKPinAnnotationColorPurple;
pin.draggable = TRUE;
return pin;
This is a tricky one! I've just implemented something similar (though I subclassed MKAnnotationView) and when I tried adding the annotationView:didChange delegate method to my view controller it didn't get called even though I was able to drag the annotation view??
I also copy/pasted your code into my view controller and it worked straight out of the box, with the delegate method being called and all!
The only thing I can think of is that instead of passing mvMap to dequeueReusableAnnotationViewWithIdentifier: try passing the mapView object that is supplied by the delegate method. Based on the code you provided above I am unable to tell if they are the same object so it might be worth a shot?
aView=(MKAnnotationView *) [mvMap dequeueReusableAnnotationViewWithIdentifier:annotation.title];
[EDIT TO ADD MY CODE AS REFERENCE]
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString* ParkAnnotationIdentifier = #"ParkAnnotationIdentifier";
MKAnnotationView* parkAnnotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ParkAnnotationIdentifier];
if (!parkAnnotationView)
{
MKAnnotationView *annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:ParkAnnotationIdentifier] autorelease];
UIImage *imageIcon = [UIImage imageNamed:#"scooterIcon.png"];
annotationView.image = imageIcon;
annotationView.draggable = YES;
return annotationView;
}
else
{
parkAnnotationView.annotation = annotation;
}
return parkAnnotationView;
}
if you are using a subview of MKPinAnnotationView and are overriding setSelected(), make sure you call super.setSelected()