How to show different image on all the annotation pins on map? - ios

I have two locations, one starting point and another end point, on these two points i want to add two different pin annotation
this is my code, the problem is i m getting the same image on both the locations
location is <+47.45025000,-122.30881700>
and location1 is <+47.62212000,-122.35410000>
- (MKAnnotationView *)mapView:(MKMapView *)mapViewer viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *mapIdentifier=#"mapIdentifier";
MKAnnotationView *myAnnotation=[mapViewer dequeueReusableAnnotationViewWithIdentifier:mapIdentifier];
CLLocationCoordinate2D parkCllocation=CLLocationCoordinate2DMake([_tripDetails[#"park_lat"] doubleValue], [_tripDetails[#"park_long"] doubleValue]);
MKPointAnnotation *jauntAnnotationPark =[[MKPointAnnotation alloc] init];
// jauntAnnotationPark.image = [UIImage imageNamed:#"pinks.jpg"];
jauntAnnotationPark.coordinate=parkCllocation;
CLLocationCoordinate2D orginCllocation=CLLocationCoordinate2DMake([_tripDetails[#"origin_lat"] doubleValue], [_tripDetails[#"origin_long"] doubleValue]);
MKPointAnnotation *jauntAnnotationOrgin =[[MKPointAnnotation alloc] init];
jauntAnnotationOrgin.coordinate=orginCllocation;
CLLocation *location = [[CLLocation alloc] initWithLatitude:[_tripDetails[#"origin_lat"] doubleValue] longitude:[_tripDetails[#"origin_long"] doubleValue]];
CLLocation *location1 = [[CLLocation alloc] initWithLatitude:[_tripDetails[#"park_lat"] doubleValue] longitude:[_tripDetails[#"park_long"] doubleValue]];
myAnnotation = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:mapIdentifier];
check=[[NSMutableArray alloc]initWithObjects:location,location1, nil];
for (NSString *location in check)
{
int i;
myAnnotation.image=[UIImage imageNamed:#"pin7#2x.png"];
}
if (!myAnnotation) {
myAnnotation = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:mapIdentifier];
}
else {
myAnnotation.annotation=annotation;
}
return myAnnotation;
}

Your code only sets one image - pin7 and your code also contains a lot of redundancy; you dequeue an annotation view into myAnnotation then alloc/init a new one then later you check if it is nil which it won't be because you just alloc/inited one.
Your check array contains CLLocation objects but you iterate the array into an NSString reference - and then don't do anything with the value anyway.
You can use this code to dequeue a view, allocate a new one if it can't be dequeued and then set the appropriate image; This code assumes that there are only two annotations and if it isn't the origin then it must be the end. If there are more than these two annotations then you need modify the code to account for that.
-(MKAnnotationView *)mapView:(MKMapView *)mapViewer viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *mapIdentifier=#"mapIdentifier";
MKAnnotationView *myAnnotation=[mapViewer dequeueReusableAnnotationViewWithIdentifier:mapIdentifier];
if (myAnnotation == nil) {
myAnnotation = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:mapIdentifier];
}
CLLocationCoordinate2D originCllocation=CLLocationCoordinate2DMake([_tripDetails[#"origin_lat"] doubleValue], [_tripDetails[#"origin_long"] doubleValue]);
if (originCllocation.latitude==annotation.coordinate.latitude && originCllocation.longitude==annotation.coordinate.longitude) {
myAnnotation.image=[UIImage imageNamed:#"startPin.png"];
} else {
myAnnotation.image=[UIImage imageNamed:#"endPin.png"];
}
return myAnnotation;
}

loop through the latitude and longitude values of your annotation coordinates.
and implement checks in view for annotation
for(int i=0; i <latArray.count; i++)
{
//annotation.coordinate.latitude
//annotation.coordinate.longitude
//compare your latitude and longitude values and change the image accordingly.
}

yup you can do it by putting condition also.
-(MKAnnotationView *)mapView:(MKMapView *)mapViewer viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation.title.isEqualToString(#"Source"))
{
myAnnotation.image=[UIImage imageNamed:#"startPin.png"];
} else {
myAnnotation.image=[UIImage imageNamed:#"endPin.png"];
}

Related

How to add Tap gesture on MKPointAnnotation to show another view with data?

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

Grouping Annotation Pins on the Same Coordinate

i have many annotations on my map, How can i grouping Annotation Pins on the Same Coordinate?, i found this but i down't know how can i use that
I think do you mean use something like a cluster on your map for grouping the pins, isn't it?
I used sometime REVClusterMap:
https://github.com/RVLVR/REVClusterMap
Is very useful to avoid to show many points on the map. With that, you show groups of annotations (the clusters) when you are far on the map, and when you zoom in, the points are appearing.
You only have to define your map like this:
REVClusterMapView *mapView;
mapView = [[REVClusterMapView alloc] initWithFrame:viewBounds];
And when you have to add and define the annotations, it will be like this:
NSMutableArray *pins = [NSMutableArray array];
for(int i=0;i<50;i++) {
...
CLLocationCoordinate2D newCoord = {lat+latDelta, lng+lonDelta};
REVClusterPin *pin = [[REVClusterPin alloc] init];
pin.title = [NSString stringWithFormat:#"Pin %i",i+1];;
pin.subtitle = [NSString stringWithFormat:#"Pin %i subtitle",i+1];
pin.coordinate = newCoord;
[pins addObject:pin];
[pin release];
}
[mapView addAnnotations:pins];
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation {
...
REVClusterPin *pin = (REVClusterPin *)annotation;
MKAnnotationView *annView;
if( [pin nodeCount] > 0 ) { //cluster
pin.title = #"___";
annView = (REVClusterAnnotationView*)
[mapView dequeueReusableAnnotationViewWithIdentifier:#"cluster"];
if( !annView )
annView = (REVClusterAnnotationView*)
[[REVClusterAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"cluster"];
annView.image = [UIImage imageNamed:#"cluster.png"];
[(REVClusterAnnotationView*)annView setClusterText:
[NSString stringWithFormat:#"%i",[pin nodeCount]]];
annView.canShowCallout = NO;
}
else { //show your code for a single annotation
...
}
I hope it will be useful :)
Have your ADClusterMapView? It works really well for us.

Open different maps with different annotation

I'm making an app with multiple annotations on a mapview. I succeeded in displaying the annotations on the mapview.
I want to use the app to find different stores in one country. So I have all the coordinates and I want that when an annotation is clicked, the Maps app gets launched and the user can get a route from his current location.
My problem is that when I use the calloutAccessoryControlTapped function, every annotation displays the information of the first coordinates I filled in.
This is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
[self plotAnnotations];
}
-(void)plotAnnotations
{
CLLocationCoordinate2D coordinate1;
coordinate1.latitude = 52.511917;
coordinate1.longitude = 4.994776;
MyLocation *annotation = [[MyLocation alloc] initWithCoordinate:coordinate1 title:#"Basic-Fit Purmerend"];
CLLocationCoordinate2D coordinate2;
coordinate2.latitude = 51.972618;
coordinate2.longitude = 5.310799;
MyLocation *annotation2 = [[MyLocation alloc] initWithCoordinate:coordinate2 title:#"Basic-Fit Aalsmeer"];
[self.mapView addAnnotation:annotation];
[self.mapView addAnnotation:annotation2];
}
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
}
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
CLLocationCoordinate2D coordinate1;
coordinate1.latitude = 52.511917;
coordinate1.longitude = 4.994776;
NSDictionary *addressDict1 = #{(NSString*)kABPersonAddressStreetKey:#"Grotenhuysweg 100, 1447 Purmerend, Nederland"};
MKPlacemark *placeMark1 = [[MKPlacemark alloc]initWithCoordinate:coordinate1 addressDictionary:addressDict1];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placeMark1];
[mapItem setName:#"Basic-Fit Purmerend"];
[mapItem setUrl:[NSURL URLWithString:#"http://www.basic-fit.nl/sportschool/Purmerend"]];
CLLocationCoordinate2D coordinate2;
coordinate2.latitude = 51.972618;
coordinate2.longitude = 5.310799;
NSDictionary *addressDict2 = #{(NSString*)kABPersonAddressStreetKey:#"Molenvliet 18A, Aalsmeer, Nederland"};
MKPlacemark *placeMark2 = [[MKPlacemark alloc]initWithCoordinate:coordinate2 addressDictionary:addressDict2];
MKMapItem *mapItem2 = [[MKMapItem alloc] initWithPlacemark:placeMark2];
[mapItem2 setName:#"Basic-Fit Aalsmeer"];
[mapItem2 setUrl:[NSURL URLWithString:#"http://www.basic-fit.nl/sportschool/aalsmeer"]];
NSArray *mapPoints = #[mapItem];
[MKMapItem openMapsWithItems:mapPoints launchOptions:nil];
NSArray *mapPoints1 =#[mapItem2];
[MKMapItem openMapsWithItems:mapPoints1 launchOptions:nil];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *identifier = #"MyLocation";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annotationView)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:#"arrest.png"];//here we use a nice image instead of the default pins
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
I eventually want to display more than 2 annotations on the map. But when I select an annotation, the data provided by coordinate1 are displayed.
How can I solve this?
Nice work so far. The problem is in the -mapView:annotationView:calloutAccessoryControlTapped: delegate method. This method is called when an annotation on the map view is tapped. You're trying to configure and open the Maps app for both of your example annotations in this delegate method which you shouldn't be doing. You should be opening the Maps app using the annotation view that you're given access to. The reason why the first annotation's details are being shown no matter what is because
NSArray *mapPoints = #[mapItem];
[MKMapItem openMapsWithItems:mapPoints launchOptions:nil];
will get called first any time you tap on an annotation.
Here's some stuff that I suggest you do.
You should modify your MyLocation class to have a NSDictionary property that will hold the address and a NSURL property to hold your URL.
So your -plotAnnotations method would look like this now:
-(void)plotAnnotations
{
CLLocationCoordinate2D coordinate1;
coordinate1.latitude = 52.511917;
coordinate1.longitude = 4.994776;
MyLocation *annotation = [[MyLocation alloc] initWithCoordinate:coordinate1 title:#"Basic-Fit Purmerend"];
// Set the address for this annotation
annotation.address = #{(NSString*)kABPersonAddressStreetKey:#"Grotenhuysweg 100, 1447 Purmerend, Nederland"};
annotation.url = [NSURL URLWithString:#"http://www.basic-fit.nl/sportschool/Purmerend"];
CLLocationCoordinate2D coordinate2;
coordinate2.latitude = 51.972618;
coordinate2.longitude = 5.310799;
MyLocation *annotation2 = [[MyLocation alloc] initWithCoordinate:coordinate2 title:#"Basic-Fit Aalsmeer"];
// Set the address for this annotation
annotation2.address = #{(NSString*)kABPersonAddressStreetKey:#"Molenvliet 18A, Aalsmeer, Nederland"};
annotation.url = [NSURL URLWithString:#"http://www.basic-fit.nl/sportschool/aalsmeer"];
[self.mapView addAnnotation:annotation];
[self.mapView addAnnotation:annotation2];
}
Now your -mapView:annotationView:calloutAccessoryControlTapped: delegate method will look like this:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
// You can retrieve your annotation using the annotation property of MKAnnotationView
MyLocation *annotation = (MyLocation *)view.annotation;
// Then you configure everything like you were doing
MKPlacemark *placeMark = [[MKPlacemark alloc] initWithCoordinate:annotation.coordinate addressDictionary:annotation.address];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placeMark];
[mapItem setName:annotation.title];
[mapItem setUrl:annotation.url];
[MKMapItem openMapsWithItems:#[mapItem] launchOptions:nil];
}
Something better to do would be to create a class called Place that has properties that stores all of your data pieces. Then you would modify your MyLocation class to initialize with your Place class. Then you would just access your Place class every time you have access to an annotation.

Plot two different color of mapview pin

I'm trying to display mapview with an array of coordinates. So, i load the latitudes and longitudes from array where those are contains. It is showing perfectly. Now, i want to display one paritcular latitude & longitude with different color pin. I've referred this answer no such different i can't see.
ViewController.m
-(void)showMap:
{
...
...
DataProvider *d = [DataProvider getInstance];
NSInteger numb = sender.view.tag;
d.colorlatitude = [[arraxy objectAtIndex:numb] objectForKey:#"lat"];
d.colorlongitude = [[arraxy objectAtIndex:numb] objectForKey:#"lng"];
[d._address removeAllObjects];
[arraxy removeObjectAtIndex:sender.view.tag];
d._address = arraxy;
MapViewController *map = [[MapViewController alloc]initWithNibName:#"MapViewController" bundle:nil];
[self.navigationController pushViewController:map animated:YES];
}
MapViewController.m
-(void)viewWillAppear:(BOOL)animated
{
DataProvider *d = [DataProvider getInstance];
[_mapView removeAnnotations:_mapView.annotations];
RegisterViewController *appDelegate = [[RegisterViewController alloc]init];
[_mapView setShowsUserLocation:YES];
[_mapView setRegion:MKCoordinateRegionMakeWithDistance([appDelegate.locationManager location].coordinate, 1000, 1000)];
[_mapView setUserTrackingMode:MKUserTrackingModeNone];
MKCoordinateRegion rregion = {{0.0,0.0},{0.0,0.0}};
rregion.center.latitude = [d.colorlatitude floatValue];
rregion.center.longitude = [d.colorlongitude floatValue];
rregion.span.latitudeDelta=0.001f;
rregion.span.longitudeDelta=0.001f;
[_mapView setRegion:rregion];
MapviewAnnotations *add = [[MapviewAnnotations alloc]init];
add.coordinate = rregion.center;
[_mapView addAnnotation:add];
if (d._address)
{
for (int i=0; i<[d._address count]; i++)
{
NSDictionary *dic=[d._address objectAtIndex:i];
MKCoordinateRegion region={{0.0,0.0},{0.0,0.0}};
region.center.latitude=[[dic objectForKey:#"lat"]floatValue];
region.center.longitude=[[dic objectForKey:#"lng"]floatValue];
region.span.latitudeDelta=0.001f;
region.span.longitudeDelta=0.001f;
[_mapView setRegion:region];
MapviewAnnotations *ann=[[MapviewAnnotations alloc]init];
ann.coordinate=region.center;
[_mapView addAnnotation:ann];
}
}
[super viewWillAppear:YES];
}
and my MKMapView's delegate method is
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if (![annotation isKindOfClass:[MapviewAnnotations class]])
{
return nil;
}
static NSString *reuseId = #"currentloc";
MKPinAnnotationView *annView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (annView == nil)
{
annView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
annView.animatesDrop = NO;
annView.canShowCallout = YES;
annView.calloutOffset = CGPointMake(-5, 5);
}
else
{
annView.annotation = annotation;
}
DataProvider *mvAnn = [DataProvider getInstance];
if (mvAnn.colorlatitude) // here i'm checking the condition.
{
annView.pinColor = MKPinAnnotationColorGreen;
}
else
{
annView.pinColor = MKPinAnnotationColorRed;
}
return annView;
}
I'm just writting the condition if the co-ordinate is there i've to plot the green color pin to that particular coordinate only. How to achieve this?
The difference between your code and the one Hinata has referred you to is that the if statement in the other code uses a value (yesno) on the annotation it is currently drawing to decide what colour to use. You are getting a value from DataProvider but not telling it which annotation you are drawing, so the instance it gives you is just what ever the instance method feels like returning at the time the map is asking for the pin. You need to tell it what you're drawing for it to decide what to put into colorlatitude
I've done this through some flags like below inside of my - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
MapviewAnnotations *mvAnn = (MapviewAnnotations *)annotation;
if (mvAnn.flag == 1)
{
annView.pinColor = MKPinAnnotationColorGreen;
}
else if (mvAnn.flag == 10)
{
annView.pinColor = MKPinAnnotationColorPurple;
}
else
{
annView.pinColor = MKPinAnnotationColorRed;
}
In my viewWillAppear i received the coordinates from DataProvider and assigned with separate MapviewAnnotations with flags and differentiate it with three type of pins simply.
Cheers!

MKMapView shows same title for multiple MKPlacemarks

I have a mkmapview that I'm dropping several placemark pins on, however I've not been able to get the pins to show the correct title on the callouts, seems to randomly show a title from the collection of pins on the map. Any ideas? Code looks like:
(void)viewDidLoad {
[super viewDidLoad];
[mapView setDelegate:self];
CLLocationCoordinate2D geos = CLLocationCoordinate2DMake([putInLat doubleValue], [putInLong doubleValue]);
aMarker = [[RNPlaceMark alloc] initWithCoordinate:geos Title:#"Location A"];
CLLocationCoordinate2D geos2 = CLLocationCoordinate2DMake([takeOutLat doubleValue], [takeOutLong doubleValue]);
bMarker = [[RNPlaceMark alloc] initWithCoordinate:geos2 Title:#"Location B"];
NSArray *annots = [[NSArray alloc] initWithObjects:putInMarker, takeOutMarker, nil];
[mapView addAnnotations:annots];
}
and
(MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id<MKAnnotation>)annotation {
NSString *title = annotation.title;
MKPinAnnotationView *pinView=(MKPinAnnotationView *)[aMapView dequeueReusableAnnotationViewWithIdentifier:title];
if(pinView==nil)
pinView=[[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:title] autorelease];
if(annotation == aMarker)
[pinView setPinColor:MKPinAnnotationColorGreen];
else if(annotation == bMarker)
[pinView setPinColor:MKPinAnnotationColorRed];
pinView.canShowCallout=YES;
pinView.animatesDrop=YES;
return pinView;
}
I switched the code to use MKPointAnnotation it worked fine, so now it looks like...
I'm executing the following code in my viewDidLoad method on the view that host the UIMapVIew:
MKPointAnnotation *myMarker = [[MKPointAnnotation alloc] init];
[myMarker setTitle:#"Hello World"];
CLLocationCoordinate2D geos = CLLocationCoordinate2DMake([myMarkerLat doubleValue], [myMarkerLong doubleValue]);
[myMarker setCoordinate:geos];
NSArray *annots = [[NSArray alloc] initWithObjects:myMarker, nil];
[mapView addAnnotations:annots];
then I have...
- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id
<MKAnnotation>)annotation
{
NSString *title = annotation.title;
MKPinAnnotationView *pinView=(MKPinAnnotationView *)[aMapView dequeueReusableAnnotationViewWithIdentifier:title];
if(pinView==nil)
pinView=[[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:title] autorelease];
//If you want to change the color of the pin you can with something like...
//if(annotation == whatEverInstanceOfAMarkerIWantToKeep)
// [pinView setPinColor:MKPinAnnotationColorGreen];
pinView.canShowCallout=YES;
pinView.animatesDrop=YES;
return pinView;
}

Resources