distinction between user annotation an other annotations - ios

please i have recently made a Map which suppose to show the user location (green pin color) and others annotations for service stations (red pins color), for the moment, i am able to show all annotations with the same color and i still unable to tell the MKMapView delegate how to make difference between two pin types and so assign to each type the right title to show.
this is my MKAnnotationView method :
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyLocation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [map dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
[annotationView setAnimatesDrop:YES];
annotationView.canShowCallout = YES;
return annotationView;
}
return nil;
}
and for my class which implement the MKAnnotation delegate i have this method :
-(id)initWithName:(NSString *)enseigneDeLaStation distanceVersLaStation:(NSString *) distanceVersLaStation coordinate:(CLLocationCoordinate2D)coordinate
{
if ((self = [super init])) {
_enseigneDeLaStation = [enseigneDeLaStation copy];
_distanceVersLaStation = [distanceVersLaStation copy];
_coordinate = coordinate;
}
return self;
}
thx in advance for your help :)
EDIT
i try to make the user location annotation like this, please if i am wrong correct me :
location2D = (CLLocationCoordinate2D){ .latitude = latitudeOfUserLocation, .longitude = longitudeOfUserLocation };
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are here" distanceVersLaStation:#"" coordinate:location2D]autorelease];
[mapView addAnnotation:annotation];
EDIT 2
Hi again, i try to make one annotation to make sure it even call the annotation method so imake this simple example :
latitudeOfUserLocation=43.2923;
longitudeOfUserLocation=5.45427;
location2D = (CLLocationCoordinate2D){ .latitude = latitudeOfUserLocation, .longitude = longitudeOfUserLocation };
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are here" distanceVersLaStation:#"coucou" coordinate:location2D]autorelease];
[mapView addAnnotation:annotation];
MKCoordinateSpan span={latitudeDelta:1,longitudeDelta:0.5};
MKCoordinateRegion region={location2D,span};
[mapView setRegion:region];
when i run the app, i see the region zoomed well which go with the 43.2923/5.45427 but i don't see the annotation, why it's not calling the annotation method,i can't move on since it's not showing the user annotation, please help, thx in advance :)
EDIT 3
Hi, i assumed that this has always relation with making difference between user and station pins, so i have declared a var codeColor, set it to 1 (the type of the user) when invoking the annotations and set it to 2(station type) when calling the annotations for the stations :
-(void)viewWillAppear:(BOOL)animated
{
codeColor=1;//it's the first type, the user one
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are right here" distanceVersLaStation:#"" coordinate:location2D]autorelease];
annotation.pinColor = MKPinAnnotationColorGreen;
[mapView addAnnotation:annotation];
}
and :
-(void)requestFinished:(ASIHTTPRequest *)request
{ codeColor=2;
[MBProgressHUD hideHUDForView:self.view animated:YES];
MyLocation *annotation=[[[MyLocation alloc]initWithName:ensStation distanceVersLaStation:distance coordinate:location2D]autorelease];
annotation.pinColor = MKPinAnnotationColorPurple;
[mapView addAnnotation:annotation];
}
and for the annotations method :
if (codeColor==2) {
annotationView.rightCalloutAccessoryView=[UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
now when testing for the first time, all is ok, the user annotation without button and the station one is with the button, but when i move from the view and i came back, all annotations are with buttons, even the user one. could you please help me there, thx in advance :)

One simple way is to add a pinColor property to your MyLocation class:
#property (nonatomic, assign) MKPinAnnotationColor pinColor;
When creating the annotation, set the pinColor:
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are here" distanceVersLaStation:#"" coordinate:location2D]autorelease];
annotation.pinColor = MKPinAnnotationColorGreen; //or red or whatever
[mapView addAnnotation:annotation];
and in the viewForAnnotation method:
//...
annotationView.canShowCallout = YES;
annotationView.pinColor = ((MyLocation *)annotation).pinColor;

Related

Add annotations to MKMapView with different images according to location of object

I've been searching for hours now to find a good tutorial on how to add annotations given a class that holds locations and images of an object (in my case, object is called as EVENT).
Check out what I've done so far, I'm calling this method setupAnnotations from viewDidLoad.
- (void)setupAnnotations {
_allEvents = [EventEntity MR_findAll];
for (EventEntity *event in _allEvents) {
AVEventAnnotationView *annotation = [[AVEventAnnotationView alloc] initWithOperator:event];
CLLocation *eventLocation = [[CLLocation alloc] initWithLatitude:[[event latitude] doubleValue] longitude:[[event longitude] doubleValue]];
annotation.coordinate = eventLocation.coordinate;
MKPlacemark *eventPlacemark = [[MKPlacemark alloc] initWithCoordinate:eventLocation.coordinate addressDictionary:nil];
MKMapItem *eventItem = [[MKMapItem alloc] initWithPlacemark:eventPlacemark];
// Im loading image from URL for or based on event object
UIImageView *imageContainer = [[UIImageView alloc] init];
[imageContainer sd_setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",fullBannerImgPath,[event bannerImg]]]];
[_bannerImagesArray addObject:imageContainer];
BOOL hasAnnotation = NO;
for (AVEventAnnotationView *ann in self.mapView.annotations) {
if([ann isKindOfClass:[AVEventAnnotationView class]])
{
if([[annotation.eventEntity dataId] isEqualToString:[ann.eventEntity dataId]])
{
hasAnnotation = YES;
break;
}
}
}
if(!hasAnnotation)
[self.mapView addAnnotation:annotation];
}
}
And here's my mapview delegate:
- (MKAnnotationView *)mapView:(MKMapView *)mapViewIn viewForAnnotation:(id <MKAnnotation>)annotation {
if (mapViewIn != self.mapView || [annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
static NSString *annotationIdentifier = #"SPGooglePlacesAutocompleteAnnotation";
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
// STUCK HERE
annotationView.image = [UIImage imageNamed:#"LocationBlue"];
annotationView.frame = CGRectMake(0, 0, 80, 80);
annotationView.draggable = NO;
annotationView.canShowCallout = YES;
return annotationView;
}
I'm new to implementing MKMapView. I just read awhile ago the difference between annotation and annotation view.
Anyway, back to my main question or my main problem: How to put annotation/annotationview to mkmapview given I have an array of EVENTS with latitude, longitude and Images?
I don't know what is AVAnnotationView but I would say you don't need it. You just have to make your Event class conform to MKAnnotation protocol, that is add the property coordinate of type CLLocationCoordinate2D to the Event class. After this just add the events to the map with addAnnotations.
In your mapView:viewForAnnotation: you determine what is the annotation that is being displayed (what is the event that is being displayed) and so you get the image you want to display (you may use tags or any other mean) and set the image for annotation view.
Or you just say something like:
if event = annotation as? AVEventAnnotationView {
//add your image and do stuff
}

Getting MapKit animateDrop to work

Helloall in MapKit I can't figure out how to get the animateDrop animation to run, I'm using 1 viewController with both CoreLocation and MapKit running on it.
I read that I need to make sure I have set a delegate from the mapview to self in viewDidLoad which I have done and also to make sure I am using MKPinAnnotationView to get access to the animateDrop property, which I think I have done also?
I'm building for iOS8 also.
Any help would be great
//I'm not showing all code just showing some of the related parts of code below
.h
//I do set standard imports UIKit, CoreLocation, MapKit etc
#interface ViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate>
//I do set various properties related. CLLocationManager, CLLocation, MKMapView
.m
- (void)viewDidLoad {
[super viewDidLoad];
self.mapView.delegate = self;
MKPointAnnotation *myAnnotation = [[MKPointAnnotation alloc] init];
myAnnotation.coordinate = CLLocationCoordinate2DMake(37.813186, 144.962979);
myAnnotation.title = #"My title";
myAnnotation.subtitle = #"My sub title";
[self.mapView addAnnotation:myAnnotation];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
// Try to dequeue an existing pin view first.
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
//pinView.animatesDrop = YES;
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Any help would be great

Displaying custom multiple pins shows wrong pins for locations

This problem has been bugging me for a couple of weeks already!
I have a tab bar application. On one tab I am entering points, and on another tab, the points are displayed on a map. Pins should be different dependent on the types of points.
The problem that I face is that every time I switch from one tab to another, the pin images change from what they should be to other images. For example, if I have four points on the map, three displayed as a circle and one as a triangle, the triangle will be moving around from one point to another. Images seem to change quite randomly.
So, this is the code:
ViewController.m
-(void) viewWillAppear:(BOOL)animated
{
// Select the type of map
if (isMapSelected == NO) {
self.mapView.mapType = MKMapTypeSatellite;
}
else {
self.mapView.mapType = MKMapTypeStandard;
}
// Add region to the map (center and span)
[self addRegion];
// Removing old annotation
[self.mapView removeAnnotations:mapLocations];
// Initializing arrays for the annotations
mapLocations = [[NSMutableArray alloc]init];
[self addAnnotation];
}
-(void) addAnnotation
{
CLLocationCoordinate2D mapLocation;
IGAMapAnnotation *mapAnnotation;
// Calculate how many points are included
NSInteger numberOfPoints = [coordinatesTempArray count];
// Annotations will be added only of the flight plan includes at least one point
if (numberOfPoints > 0)
{
// Trying to add coordinates from the array of coordinates
for (NSInteger i=0; i < ([coordinatesTempArray count]); i++) {
mapAnnotation = [[IGAMapAnnotation alloc]init];
// Taking a point in the array and getting its coordinates
self.mapCoordinates = [coordinatesTempArray objectAtIndex:i];
// Getting a point in the array and getting its lattitude and longitude
self.mapLatitude = [[self.mapCoordinates objectAtIndex:0]doubleValue];
self.mapLongitude = [[self.mapCoordinates objectAtIndex:1]doubleValue];
// Assigning the point coordinates to the coordinates to be displayed on the map
mapLocation.latitude = self.mapLatitude;
mapLocation.longitude = self.mapLongitude;
// Adding coordinates and title to the map annotation
mapAnnotation.coordinate = mapLocation;
mapAnnotation.title = [navaidNamesTempArray objectAtIndex:i];
mapAnnotation.subtitle = nil;
mapAnnotation.navaidType = [navaidTypesTempArray objectAtIndex:i];
// Adding the annotation to the array that will be added to the map
[mapLocations addObject:mapAnnotation];
}
// Adding annotations to the map
[self.mapView addAnnotations:mapLocations];
}
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if([annotation isKindOfClass:[IGAMapAnnotation class]])
{
IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"IGAMapAnnotation"];
if (annotationView == nil)
annotationView = myLocation.annotationView;
else
annotationView.annotation = annotation;
return annotationView;
}
else
return nil;
}
IGAMapAnnotation.m
#synthesize coordinate = _coordinate;
#synthesize title = _title;
#synthesize subtitle = _subtitle;
#synthesize type = _type;
// Tried to have this init method but was never able to make it work. Without it, the program crashes too!!!!
-(id)initWithTitle:(NSString *)newTitle Type:(NSString *)type Location:(CLLocationCoordinate2D) newCoordinate
{
self = [super init];
if (self) {
_title = newTitle;
_coordinate = newCoordinate;
_type = type;
}
return self;
}
-(MKAnnotationView *) annotationView {
MKAnnotationView *annotationView = [[MKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:#"IGAMapAnnotation"];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if ([self.type isEqual: #"A"] || [self.type isEqual: #"B"] || [self.type isEqual: #"C"])
{
annotationView.image = [UIImage imageNamed:#"circle.png"];
}
else if ([self.type isEqual: #"D"])
{
annotationView.image = [UIImage imageNamed:#"triangle.png"];
}
else if ([self.type isEqual: #"E"])
{
annotationView.image = [UIImage imageNamed:#"square.png"];
}
else
{
annotationView.image = [UIImage imageNamed:#"oval.png"];
}
return annotationView;
}
#end
This is it. So far, the behaviour makes no sense to me.
Thanks for your help!
It sounds like an annotation view re-use issue.
When the annotations are re-displayed, they are re-using views with the images of previous annotations. The image property in the view is not being updated as it should be when it is re-used for another annotation.
In the viewForAnnotation delegate method, this code looks wrong:
MKAnnotationView *annotationView = [mapView dequeue...
if (annotationView == nil)
annotationView = myLocation.annotationView;
else
annotationView.annotation = annotation;
If the dequeue returns a view (ie. a previously-created view that may have been created for an annotation of a different type), its annotation property is updated but its image property is not updated.
The existing code only sets the image property when creating a new annotation view (when dequeue returns nil).
Right now, the annotation view creation and image-setting code is in the annotation model class IGAMapAnnotation. It would be better to create a custom MKAnnotationView class that automatically updates the image property whenever its annotation property is updated.
However, another alternative is to put all the logic in the viewForAnnotation delegate method itself (and remove the annotationView method from the IGAMapAnnotation class).
Example of the updated viewForAnnotation delegate method:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if (! [annotation isKindOfClass:[IGAMapAnnotation class]])
{
//return default view if annotation is NOT of type IGAMapAnnotation...
return nil;
}
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"IGAMapAnnotation"];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"IGAMapAnnotation"];
//these properties don't change per annotation
//so they can be set only when creating a new view...
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
annotationView.annotation = annotation;
}
//whether we are using a completely new view or a re-used view,
//set the view's image based on the current annotation...
IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;
if ([myLocation.type isEqual: #"A"] || [myLocation.type isEqual: #"B"] || [myLocation.type isEqual: #"C"])
{
annotationView.image = [UIImage imageNamed:#"circle.png"];
}
else if ([myLocation.type isEqual: #"D"])
{
annotationView.image = [UIImage imageNamed:#"triangle.png"];
}
else if ([myLocation.type isEqual: #"E"])
{
annotationView.image = [UIImage imageNamed:#"square.png"];
}
else
{
annotationView.image = [UIImage imageNamed:#"oval.png"];
}
return annotationView;
}

iOS - MKMapView - Draggable Annotations

I have the annotation ready to go, but trying to figure out on how to make it draggable with my code:
-(IBAction) updateLocation:(id)sender{
MKCoordinateRegion newRegion;
newRegion.center.latitude = mapView.userLocation.location.coordinate.latitude;
newRegion.center.longitude = mapView.userLocation.location.coordinate.longitude;
newRegion.span.latitudeDelta = 0.0004f;
newRegion.span.longitudeDelta = 0.0004f;
[mapView setRegion: newRegion animated: YES];
CLLocationCoordinate2D coordinate;
coordinate.latitude = mapView.userLocation.location.coordinate.latitude;
coordinate.longitude = mapView.userLocation.location.coordinate.longitude;
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate: coordinate];
[annotation setTitle: #"Your Car is parked here"];
[annotation setSubtitle: #"Come here for pepsi"];
[mapView addAnnotation: annotation];
[mapView setZoomEnabled: YES];
[mapView setScrollEnabled: YES];
}
Thanks in advance!
To make an annotation draggable, set the annotation view's draggable property to YES.
This is normally done in the viewForAnnotation delegate method.
For example:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *reuseId = #"pin";
MKPinAnnotationView *pav = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (pav == nil)
{
pav = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
pav.draggable = YES;
pav.canShowCallout = YES;
}
else
{
pav.annotation = annotation;
}
return pav;
}
If you need to handle when the user stops dragging and drops the annotation, see:
how to manage drag and drop for MKAnnotationView on IOS?
In addition, your annotation object (the one that implements MKAnnotation) should have a settable coordinate property. You are using the MKPointAnnotation class which does implement setCoordinate so that part's already taken care of.

Mapkit new annotations with pin without popup

i've just created a new app, and i've implemented a map in a view.
I've created the map with some personal annotation but, when the user touch the pin, doesn't appear anything. I've tried to set the colour of the pin but nothing seem's to work. I need that the user, when touch the pin, can touch the disclosure button on the popup, to use "native maps".
Now, when i touch the pin, this one become darker, but nothing else.
Can someone help me? Please!!
io ne avrei bisogno, per far aprire poi un disclosure e far aprire l'app nativa mappe per creare il percorso!! Se ora tocco il pin, questo diventa piĆ¹ scuro ma non succede nulla! non riesco nemmeno ad agire su di loro per cambiare colore, immagini,.... ho guardato i tutorial ma non trovo l'errore!
header subclass
#import <Foundation/Foundation.h>
#import <MapKit/Mapkit.h>
#interface myAnnotation : NSObject <MKAnnotation>{
CLLocationCoordinate2D coordinate;
NSString *titolo;
NSString *sottotitolo;
}
#property(nonatomic,assign) CLLocationCoordinate2D coordinate;
#property(nonatomic,copy) NSString *titolo;
#property(nonatomic,copy) NSString *sottotitolo;
#end
implementation subclass
#implementation myAnnotation
#synthesize titolo;
#synthesize sottotitolo;
#synthesize coordinate;
-init{
return self;
}
#end
file .m view controller
CLLocation *userLoc = myMapView.userLocation.location;
CLLocationCoordinate2D userCoordinate = userLoc.coordinate;
NSLog(#"user latitude = %f",userCoordinate.latitude);
NSLog(#"user longitude = %f",userCoordinate.longitude);
myMapView.delegate=self;
NSMutableArray* annotations=[[NSMutableArray alloc] init];
CLLocationCoordinate2D theCoordinate1;
theCoordinate1.latitude = 45.;
theCoordinate1.longitude = 7.;
CLLocationCoordinate2D theCoordinate2;
theCoordinate2.latitude = 45.;
theCoordinate2.longitude = 12.;
CLLocationCoordinate2D theCoordinate3;
theCoordinate3.latitude = 45.;
theCoordinate3.longitude = 8.;
CLLocationCoordinate2D theCoordinate4;
theCoordinate4.latitude = 43.;
theCoordinate4.longitude = 7.;
myAnnotation* myAnnotation1=[[myAnnotation alloc] init];
myAnnotation1.coordinate=theCoordinate1;
myAnnotation1.titolo=#"xxxx";
myAnnotation1.sottotitolo=#"xxx";
myAnnotation* myAnnotation2=[[myAnnotation alloc] init];
myAnnotation2.coordinate=theCoordinate2;
myAnnotation2.titolo=#"yyyy";
myAnnotation2.sottotitolo=#"yyyy";
myAnnotation* myAnnotation3=[[myAnnotation alloc] init];
myAnnotation3.coordinate=theCoordinate3;
myAnnotation3.titolo=#"zzz";
myAnnotation3.sottotitolo=#"zzz";
myAnnotation* myAnnotation4=[[myAnnotation alloc] init];
myAnnotation4.coordinate=theCoordinate4;
myAnnotation4.titolo=#"kkk";
myAnnotation4.sottotitolo=#"kkk";
[myMapView addAnnotation:myAnnotation1];
[myMapView addAnnotation:myAnnotation2];
[myMapView addAnnotation:myAnnotation3];
[myMapView addAnnotation:myAnnotation4];
[annotations addObject:myAnnotation1];
[annotations addObject:myAnnotation2];
[annotations addObject:myAnnotation3];
[annotations addObject:myAnnotation4];
NSLog(#"%d",[annotations count]);
and then this snippet to show and personalize the pin
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:
(id <MKAnnotation>)annotation {
MKPinAnnotationView *pinView = nil;
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil ) pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinView.pinColor = MKPinAnnotationColorPurple;
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
}
else {
[mapView.userLocation setTitle:#"I am here"];
}
return pinView;
}
The MKAnnotation protocol requires that the class responds to title and subtitle. The properties must be named exactly like that.
Although you can also have your own differently named properties for the same, the map view will not call them (it is looking for title and subtitle).
For the disclosure button, in viewForAnnotation, set the rightCalloutAccessoryView to a UIButton and respond to its tap in the calloutAccessoryControlTapped delegate method.
In that delegate method, you can access the annotation object using (myAnnotation *)view.annotation and then call openURL to open the Maps app.

Resources