MKMapView switches between pin color annotations - ios

I have a bunch of pins on my map, some red and some green. The initial coloring is ok. However, when I use the map view and tap on some green ones, some reds will change to green. That probably happens when they are outside of the current view area and moved into the view area.
Ideas anyone?
Here's my code snip from :
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id < MKAnnotation >)annotation{
if(((MyAnnotation*)annotation).isGreen){
AnnotationViewID = #"MyAnnotationGreen";
}else{
AnnotationViewID = #"MyAnnotationRed";
}
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
}

You should use the isGreen property of your MyAnnotation object to assign the color to your MKPinAnnotationView object. The reuse code could give you an object that doesn't have all the properties set right, especially since you are using the exact same class under different identifier. You shouldn't rely on the validity of all property values of a dequeue object from view caches (such as uitableview dequeue).
do something like:
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
}
[annotationView setPinColor:(annotation.isGreen)? MKPinAnnotationColorGreen : MKPinAnnotationColorRed];

Related

Custom MKAnnotationView expandable without callout

I want to create custom MKAnnotationView (with image) without a callout, but expandable after touch. Here is what i have in mind:
1) First the MKAnnotation looks like this:
2) Then after tap on it this should expand and looks like this:
I've started with customing MKAnnotationView and have a class:
#interface CustomPinAnnotation : NSObject <MKAnnotation>
The class have method:
-(MKAnnotationView*)annotationView {
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:self reuseIdentifier:#"AnnotationIdentifier"];
annotationView.enabled = YES;
annotationView.image = [[UIImage imageNamed:#"star"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
return annotationView;
}
And what i try to do is set a customView as a subview to the MKAnnotationView, but when i don't set The image it will not responding (this is pretty logical after i've think about it), but got the feeling that I'm doing something very nasty here, and should be a way to override MKAnnotationView somehow.
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
enemyAnnotationView.image = [UIImage imageNamed:#"firstImage.png"];
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
enemyAnnotationView.image = [UIImage imageNamed:#"SecondImage.png"];
}
Try like this first method is for the View for annotation that time your first image will be appears,
Second method will run when user select annotation

New annotation create each time - dequeueReusableAnnotationViewWithIdentifier

This is my code:
- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation class] == MKUserLocation.class) {
return nil;
}
static NSString *identifier=#"an";
MKAnnotationView *pinView = nil;
pinView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (pinView == nil)
{
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
pinView.canShowCallout = YES;
NSLog(#"NEW ONE CREATED");
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
It seems that is not working and pinView is always nil because I can see the nslog for each pin created.
Two thoughts:
Don't assume that just because an annotation has scrolled off the current map view's current region, that it is automatically available for being dequeued and reused for another annotation immediately. It's quite possible that MKMapView is going to hang onto annotation views, not making them available for reuse immediately. For example, I could imagine some internal optimization that might hang on to annotation views that are near the map's current region in case that the user scrolls their map such that that previous annotation view is now visible again. MKMapView probably wants to avoid creating and recreating the same annotation view as the user scrolls the MKMapView back and forth.
In my experience, you have to scroll some distance before the old annotation views are made available for reuse.
This is extremely unlikely, but in addition to my observation above, we should note that your viewForAnnotation references some external variable, mapView, rather than using the aMapView that was passed as a parameter to the method. Most likely this is some instance variable that is pointing to the same MKMapView, and everything is fine, but if that mapView variable is nil, the dequeueReusableAnnotationViewWithIdentifier will always return nil, too. You might want to change your viewForAnnotation to use the aMapView parameter to remove this ambiguity.

Telling the difference between UserLocation Pin and user added pins

I am trying to solve a problem that I'm not sure how to solve. In my app, when the mapkit launches, I drop a pin at the user's current location. The mapkit delegates to viewForAnnotation which sets the pin's color which works fine.
The issue I'm running into is I cannot tell the annotations apart so I can apply a different color to "user added locations" vs. my "current location" pin. I would like to add a button so they can delete any pins they add but not be able to delete their "current location" pin. I can't seem to figure out how to extract any identifiable pieces of information like title or subtitle of the pin.
Thanks in advance for your help.
Here's my code...
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
NSLog(#"OAAssignmentGPSViewController.m : mapView viewForAnnotation");
if([annotation isKindOfClass: [MKUserLocation class]])
return nil;
NSLog(#" mapView.userLocation.title = %#", self.mapView.userLocation.title);
static NSString* annotationIdentifier = #"currentlocation";
MKPinAnnotationView *myPinView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (!myPinView) {
myPinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil] ;
myPinView.pinColor = MKPinAnnotationColorRed;
myPinView.canShowCallout = YES;
myPinView.animatesDrop = YES;
NSLog(#"mapView.description %#", self.mapView.userLocation.title);
if( annotation != self.mapView.userLocation)<<<<<----how do I check for UserLocation
{
myPinView.pinColor = MKPinAnnotationColorGreen;
myPinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
}
return myPinView;
}
Updating this for other newbies, this was the answer...
if ([annotation isKindOfClass:[MKUserLocation class]]) ....{
this is the current location pin
}else {
these are you custom locations pins
}
The only thing I can think of is to subclass MKPinAnnotationView and add a simple property to index it. Add your pins to an array as they're created and increment the index number. Then, for your "delete all pins" method, something like this where you check the index property of the pin to make sure it's not the first one:
-(IBAction)deleteAllPins
{
for (id pin in self.pinsArray) {
if (pin.indexNumber >= 1) { //This is not the first pin...
// Delete the pin
}
}
}
That's what I would try, anyway. Sorry I don't have time to test it out myself. Hopefully it will get you started. Good luck.

Setting multiple pins on an MKMapView, and have the Callout View show the correct information?

I have an array of objects, which have the information for each pin on my map. I am able to add those with their respective coordinates onto the map using [mapView addAnnotions:array];. But when it comes to selecting a pin, and then showing the Callout view for that specific pin(using the right pin location and the right information from my array), I get lost. I also do not entirely know how Callout views work for multiple pins. I've tried looking at Apple Sample Code, but it has not helped very much, and Googling the problem does not help either.
Simple version: How are you supposed to have many pins on a map, and differentiate them when they get selected and when getting called for a callout view?
Edit: For example, how the Maps app on the iPhone works with showing the several locations of businesses, and when you tap them the correct Name and link to said business appears.
try this code
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MNMyLocation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [atmLocatorMap dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
//annotationView.image=[UIImage imageNamed:#"arrest.png"];
return annotationView;
}
return nil;
}

Is there a way to subclass the MKAnnotationView used for the MKUserLocation blue dot?

I've created a custom annotation view by subclassing MKAnnotationView. This class also creates a custom callout (info pop-up 'bubble') view which is skinned to match my app.
I also want to be able to reskin the callout bubble for the user location dot, but it seems as though the only control I have over that view is whether it is overridden completely or not, by using the following inside the mapView:viewForAnnotation: method:
if(annotation == self.mapView.userLocation)
{
return nil;
}
But what I really want to do is find out what annotation view MapKit is using for the user location blue dot, and then subclass it so I can skin its callout bubble... Or is there another way? Or just no way at all?
I am not sure this will help you, but you can use the default user location annotation view, then steal the view in mapView:didSelectAnnotationView::
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
if (view == [mapView viewForAnnotation:mapView.userLocation]) {
// do what you want to 'view'
// ...
}
// ...
}
I have used this trick to change the callout title and subtitle, and add an image using leftCalloutAccessoryView. However, I haven't tried totally replacing the callout, so I don't know if it's possible.
You can use
if ([annotation isKindOfClass:[MKUserLocation class]]) { // or if(annotation == self.mapView.userLocation)
MKAnnotationView * annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"MyLocation"];
if (annotationView == nil) {
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"MyLocation"] autorelease];
annotationView.canShowCallout = NO;
annotationView.image = [UIImage imageNamedWithBrand:#"MyLocationPin.png"];
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
I think it is not possible directly, but you can override some methods in runtime with this: http://theocacao.com/document.page/266

Resources