I have several annotation points. What I want to do is when I click an annotation point I want to display that data. I have a custom Annotation class with a title and an NSDictionary. The dictionary contains an image URL and ID. I want to fetch these when I click on a specific annotation.
EDIT: I know about the didSelectAnnotation, but how do I access the data?
-(void)annotations{
CLLocationCoordinate2D pinPoint;
for (NSDictionary * dict in _dataArray) {
pinPoint.latitude =[[dict valueForKey:#"lat"] doubleValue];
pinPoint.longitude = [[dict valueForKey:#"lng"] doubleValue];
_myAnnotation = [[MapViewAnnotation alloc]initWithTitle:[dict valueForKey:#"name"]andCoordinate:pinPoint andData:dict];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:pinPoint addressDictionary:nil] ;
_destination = [[MKMapItem alloc] initWithPlacemark:placemark];
_myAnnotation.title=[dict valueForKey:#"name"];
[self.mapKit addAnnotation:_myAnnotation];
}
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapKit setRegion:[self.mapKit regionThatFits:region] animated:YES];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(MapViewAnnotation*)annotation
{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MapViewAnnotation class]])
{
// Try to dequeue an existing pin view first.
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
NSLog(#"%#",[annotation.data valueForKey:#"name"]);
pinView.image = [UIImage imageNamed:#"image"];
pinView.calloutOffset = CGPointMake(0, 32);
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinView.rightCalloutAccessoryView = rightButton;
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
[request setTransportType:MKDirectionsTransportTypeWalking];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = _destination;
request.requestsAlternateRoutes = NO;
MKDirections *directions =
[[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle Error
} else {
[self showRoute:response];
}
}];
}
EDIT 2nd :
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
MapViewAnnotation * annotation = (MapViewAnnotation *) view;
NSLog(#"%#",[annotation.data valueForKey:#"name"]);
NSURL *url =[NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:#"SPOTTD_profilePic"]];
NSData *imageData = [NSData dataWithContentsOfURL:url];
_imgMyProfile.image = [UIImage imageWithData:imageData];
}
You can use the didSelectAnnotationView method, in combination with the annotation property of the MKAnnotationView:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
if ([view.annotation isKindOfClass:[MapViewAnnotation class]]) {
MapViewAnnotation *annotation = (MapViewAnnotation)view.annotation;
}
}
After you have safely cast the annotation to your custom type, you can access its properties like the NSDictionary.
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSString *latPoint2 = [NSString stringWithFormat:#"%.6f", view.annotation.coordinate.latitude];
NSString *longPoint2 =[NSString stringWithFormat:#"%.6f", view.annotation.coordinate.longitude];
There is one more method for annotation which is
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{}.In this method you can show your data on click of annotation.Hope this will help you. If any query let me know. Thanks
Related
I have a an array of latitude and longitude and using for loop am displaying the MKPointAnnotation on the map. I want to show a view as a popup with data when the specific MKPointAnnotation is tapped.
Here is my code -
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 10000, 10000);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
[_locationManager stopUpdatingLocation];
NSArray *set = [[NSArray alloc] init];
for (int i = 0; i < _json.count; i++) {
_name = [_json[i] valueForKey:#"name"];
_class = [_json[i] valueForKey:#"class"];
set = [_json[i] valueForKey:#"set"];
if (setFreeHour.count != 0) {
for (int j=0;j<set.count;j++) {
NSDictionary *dict = [[NSDictionary alloc] init];
dict = set[j];
_lat = dict[#"latitude"];
_longi = dict[#"longitude"];
CLLocationCoordinate2D coordinate;
coordinate.latitude = [_lat doubleValue];
coordinate.longitude = [_longi doubleValue];
// Add an annotation
MKPointAnnotation *point1 = [[MKPointAnnotation alloc] init];
point1.coordinate = CLLocationCoordinate2DMake(coordinate.latitude, coordinate.longitude);
point1.title = _name;
point1.subtitle = _class;
[self.mapView addAnnotation:point1];
}
}
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
// Try to dequeue an existing pin view first.
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView) {
// If an existing pin view was not available, create one.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"annotation"];
pinView.calloutOffset = CGPointMake(0, 0);
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(showDetails)];
[pinView addGestureRecognizer:tap];
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
- (void)showDetails{
self.popup.hidden = NO;
}
//PS: popup is a view that contains labels. I want to pass data from MKPointAnnotation to the view
Why don't you use mapView(_:didSelect:) method instead of UITapGestureRecognizer?
(void)mapView:(MKMapView *)mapview didSelectAnnotationView:(MKAnnotationView *)view {
// 1. get data from view(MKAnnotationView)
// 2. pass data to another view
}
https://developer.apple.com/documentation/mapkit/mkmapviewdelegate/1452393-mapview
I am trying get the coordinate of each pin I select on my map. Pins are the local search results that users search on the map. I have an issue that every pin I select it give me the same value. Can anyone help me with this please? Thanks in advance.
- (IBAction)searchAction:(id)sender {
[sender resignFirstResponder];
[self.mapView removeAnnotations:[self.mapView annotations]];
[self performSearch]; }
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"current"];
//mypin.pinColor = MKPinAnnotationColorPurple;
mypin.backgroundColor = [UIColor clearColor];
UIButton *goToDetail = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mypin.rightCalloutAccessoryView = goToDetail;
mypin.draggable = NO;
mypin.highlighted = YES;
mypin.animatesDrop = TRUE;
mypin.canShowCallout = YES;
return mypin;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
MKPointAnnotation *annotation = view.annotation;
self.tappedCoord = annotation.coordinate;
// Longs are the same for every pin I select
NSLog(#"%f", [[view annotation] coordinate].longitude);
}
- (void)performSearch {
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = _searchText.text;
request.region = _mapView.region;
self.matchingItems = [[NSMutableArray alloc] init];
MKLocalSearch *search = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if (response.mapItems.count == 0)
NSLog(#"No Matches");
else
for (MKMapItem *item in response.mapItems)
{
[self.matchingItems addObject:item];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc]init];
annotation.coordinate = item.placemark.coordinate;
annotation.title = item.name;
annotation.subtitle = [NSString stringWithFormat:#"%#, %# %#",
item.placemark.addressDictionary[#"Street"],
item.placemark.addressDictionary[#"State"],
item.placemark.addressDictionary[#"ZIP"]];
//NSLog(#"%#", item.placemark.addressDictionary);
[_mapView addAnnotation:annotation];
}
}];
}
I am new to xcode and i hope someone can help me with my code, and point me how to solve my issue. i've been looking at the internet, but really i couldnt figure it out.
How can i go from a map view to a detail view, bringing the "ID" of the pin with it and print it in a label.
when i click on the arrow for the annotation, my simulator crashes.
Please any ideas, how to approach it and solve it ?
( basicly i want to get the ID of the pin, and send it to a server through JSON and then move to the Detailview, but the next step )
Here is what i did so far :
My Location.m ( view controller for the map )
#import "My_Location.h"
#import "DetailViewController.h"
// ------ FUNCTION TO GET COORDINATES IN JSON FORMAT -------
- (void)retrieveData_Location
{
NSURL * url = [NSURL URLWithString:#"............./Pharmacies.php"];
NSData * data = [NSData dataWithContentsOfURL:url];
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSMutableArray *newAnnotations = [NSMutableArray array];
CLLocationCoordinate2D location;
for (NSDictionary *dictionary in array)
{
MKPointAnnotation *newAnnotation = [[MKPointAnnotation alloc] init];
location.latitude = [dictionary[#"lat"] doubleValue];
location.longitude = [dictionary[#"lon"] doubleValue];
newAnnotation.title = dictionary[#"name"];
newAnnotation.coordinate = location;
[newAnnotations addObject:newAnnotation];
[newAnnotation release];
}
[self.MyLocation addAnnotations:newAnnotations];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation {
if([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *identifier = #"myAnnotation";
MKPinAnnotationView * annotationView = (MKPinAnnotationView*)[self.MyLocation dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annotationView)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.pinColor = MKPinAnnotationColorPurple;
annotationView.animatesDrop = YES;
annotationView.canShowCallout = YES;
}else {
annotationView.annotation = annotation;
}
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
[self performSegueWithIdentifier:#"Details" sender:view];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Details"])
{
MKAnnotationView *annotationView = sender;
[segue.destinationViewController setAnnotation:annotationView.annotation];
}
}
Take_Photo is my detailviewcntroller.
And my storybaord look like this :
Mylocation View controller -> ( Segue: identifier ( Take_Photo )) -> Take_Photo view Controller
trying to pass my annotation's data (name, address, phone #, url, description, etc) to a DetailViewController with a table. stuck----please read the code. the data isnt passed with calloutAccessoryTapped. Help?
- (IBAction)gasButton:(id)sender {
[self.mapView removeAnnotations:self.mapView.annotations];
self.localSearchRequest = [[MKLocalSearchRequest alloc] init];
self.localSearchRequest.region = self.mapView.region;
self.localSearchRequest.naturalLanguageQuery = #"gas station";
self.localSearch = [[MKLocalSearch alloc] initWithRequest:self.localSearchRequest];
[self.localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if(error){
NSLog(#"localSearch startWithCompletionHandlerFailed! Error: %#", error);
return;
} else {
for(mapItem in response.mapItems){
MKPointAnnotation *zip = [[MKPointAnnotation alloc] init ];
zip.coordinate = mapItem.placemark.location.coordinate;
zip.title = mapItem.name;
self.mapView.delegate = self;
[self.mapView addAnnotation: zip];
[self.mapView selectAnnotation:zip animated:YES];
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow];
NSLog(#"%# - 1", mapItem.name);
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:zip.coordinate.latitude longitude:zip.coordinate.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:self.mapView.userLocation.coordinate.latitude longitude:self.mapView.userLocation.coordinate.longitude];
CLLocationDistance distance = [loc1 distanceFromLocation:loc2];
NSString *dist = [[NSString alloc] initWithFormat:#"%.2f miles", distance * 0.000621371192];
zip.subtitle = dist;
}
}
}];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
MKPinAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"MYVC"];
if ([annotation isKindOfClass:[MKUserLocation class]])
{
return nil;
}
else if ([annotation isKindOfClass: [MKPointAnnotation class] ])
{
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.enabled = YES;
annotationView.animatesDrop = YES;
annotationView.pinColor = MKPinAnnotationColorGreen;
annotationView.canShowCallout = YES;
NSLog(#"%# - 2", mapItem.name);
return annotationView;
}
return nil;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#"%# - tapped", mapItem.name);
//STUCK HERE - mapItem.name is (null)
}
mapItem exists in the for loop of your gasButton function, no where else as far as I can see. You've created an annotation (zip) and added it to your map. In viewForAnnotation you are given that annotation as a parameter and asked to make an annotationView from it. In calloutAccessoryControlTapped you are given an annotationView and told it has been tapped. You need to follow the chain back to your data. From the annotationView get the annotation and from the annotation get your name.
MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#"%# - tapped", view.annotation.title);
}
In my map annotations, I have a UIButton as each accessory view in the callouts. In the - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control method, how do I figure out which accessory view was touched to handle each the events? Here's my code:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKPinAnnotationView *MyPin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"current"];
UIButton *calloutButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
UIButton *directionsButton = [UIButton buttonWithType:UIButtonTypeCustom];
directionsButton.frame = CGRectMake(0, 0, 23, 23);
[directionsButton setBackgroundImage:[UIImage imageNamed:#"directions.png"] forState:UIControlStateNormal];
MyPin.leftCalloutAccessoryView = directionsButton;
MyPin.rightCalloutAccessoryView = calloutButton;
MyPin.draggable = NO;
MyPin.highlighted = NO;
MyPin.animatesDrop= YES;
MyPin.canShowCallout = YES;
MyPin.pinColor = MKPinAnnotationColorRed;
return MyPin;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
Annotation *ann = view.annotation;
if ([control tag] == 1) {
CLLocationCoordinate2D currentCoords = {ann.coordinate.latitude, ann.coordinate.longitude};
MKPlacemark *place = [[MKPlacemark alloc] initWithCoordinate: currentCoords addressDictionary:nil];
MKMapItem *destination = [[MKMapItem alloc] initWithPlacemark: place];
destination.name = ann.title;
destination.url = [NSURL URLWithString:#"http://www.wccca.com/PITS"];
NSArray *items = [[NSArray alloc] initWithObjects: destination, nil];
NSDictionary *options = [[NSDictionary alloc] initWithObjectsAndKeys:
MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsDirectionsModeKey, nil];
[MKMapItem openMapsWithItems: items launchOptions: options];
}
if ([control tag] == 2) {
MKCoordinateRegion region;
region.center.latitude = ann.coordinate.latitude;
region.center.longitude = ann.coordinate.longitude;
region.span.latitudeDelta = 0.02;
region.span.longitudeDelta = 0.02;
[self.mapView setRegion:region animated:YES];
}
}
Rather than setting and using tags, you could just check if control is the left or right accessory view:
if (control == view.leftCalloutAccessoryView) {
//handle left control tap...
}
else
if (control == view.rightCalloutAccessoryView) {
//handle right control tap...
}