Apple MapKit with Kingpin annotations clustering custom annotations - ios

I have built a Map application that uses the Kingpin map pin clustering library, (found here) at present the library succeeds in approximating the position of the pins and placing the cluster pin. However, the original pins are never removed as seen here. I think the relevant code is this:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
MKAnnotationView *annotationView = nil;
if([annotation isKindOfClass:[KPAnnotation class]]){
KPAnnotation *kingpinAnnotation = (KPAnnotation *)annotation;
if ([kingpinAnnotation isCluster]) {
annotationView=(MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"cluster"];
if (annotationView==nil){
annotationView=[[MKAnnotationView alloc]initWithAnnotation:kingpinAnnotation reuseIdentifier:#"cluster"];
annotationView.canShowCallout=YES;
annotationView.image=[UIImage imageNamed:#"icon_notif_recall.png"];
annotationView.frame=CGRectMake(0,0,25,25);
}
}else{
annotationView=(MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pin"];
if (annotationView==nil){
annotationView=[[MKAnnotationView alloc]initWithAnnotation:[kingpinAnnotation.annotations anyObject]reuseIdentifier:#"pin"];
annotationView.canShowCallout=YES;
annotationView.image=[UIImage imageNamed:#"icon_notif_recall.png"];
annotationView.frame=CGRectMake(0,0,25,25);
}
}
return annotationView;
}else if([annotation isKindOfClass:[REC_CustomAnnotation class]]){//Check that is our custom pin class
REC_CustomAnnotation *myLocation = (REC_CustomAnnotation *)annotation;
MKAnnotationView *annotationView=[mapView dequeueReusableAnnotationViewWithIdentifier:#"REC_CustomAnnotation"];
if(annotationView==nil){
annotationView=myLocation.annotationView;
}else{
annotationView.annotation=annotation;
}
return annotationView;
}else{
return annotationView;
}
}
but I am really not sure what is wrong. Any thoughts on what the problem is or things to try would be greatly appreciated.

As it turned out, the function posted above was in fact the problem. However, I was on the complete wrong track in terms of understanding how kingpin worked. Got everything working with this:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
MKAnnotationView *annotationView = nil;
if ([annotation isKindOfClass:[KPAnnotation class]]) {
KPAnnotation *a = (KPAnnotation *)annotation;
if ([annotation isKindOfClass:[MKUserLocation class]]){
return nil;
}
if (a.isCluster) {
annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"cluster"];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:a reuseIdentifier:#"cluster"];
}
annotationView.image=[UIImage imageNamed:#"icon_notif_recall.png"];
annotationView.frame=CGRectMake(0,0,25,25);
}else {
annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pin"];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:[a.annotations anyObject] reuseIdentifier:#"pin"];
}
KPAnnotation *thisKPAnnot=(KPAnnotation *)annotation;
NSMutableArray *arrayOfAnnots = [NSMutableArray arrayWithArray:[[thisKPAnnot annotations] allObjects]];
if([arrayOfAnnots count]==1){
REC_CustomAnnotation *thisAnnot=(REC_CustomAnnotation *)[arrayOfAnnots objectAtIndex:0];
if(thisAnnot.type==1){
annotationView.image=[UIImage imageNamed:#"icon_notif_facebook.png"];
}else if(thisAnnot.type==2){
annotationView.image=[UIImage imageNamed:#"icon_notif_twitter.png"];
}else if(thisAnnot.type==3){
annotationView.image=[UIImage imageNamed:#"icon_notif_instagram.png"];
}else if(thisAnnot.type==4){
annotationView.image=[UIImage imageNamed:#"icon_notif_foursquare.png"];
}else if(thisAnnot.type==5){
annotationView.image=[UIImage imageNamed:#"icon_notif_camera.png"];
}else{
annotationView.image=[UIImage imageNamed:#"icon_notif_recall.png"];
}
}else{annotationView.image=[UIImage imageNamed:#"icon_notif_recall.png"];}
annotationView.frame=CGRectMake(0,0,25,25);
}
annotationView.canShowCallout = YES;
}
return annotationView;
}
I hope this ends up helping someone in the future.

Related

How to use different MKAnnotationView for 2 different MKPointAnnotation on the same MKMapView

I have 2 MKPointAnnotation and i want to display them on map with two different pins(MKAnnotationView having image).
// MKPointAnnotation - 1
CLLocationCoordinate2D cordinate;
cordinate.latitude = [_latitudeString doubleValue];
cordinate.longitude = [_longitudeString doubleValue];
MKPointAnnotation *point1 = [[MKPointAnnotation alloc] init];
point1.coordinate = CLLocationCoordinate2DMake(cordinate.latitude, cordinate.longitude);
[self.mapView addAnnotation:point1];
P.S - When i get second MKPointAnnotation i needed self zoom on that area.
// MKPointAnnotation - 2
CLLocationCoordinate2D cordinate;
cordinate.latitude = [_latStr doubleValue];
cordinate.longitude = [_longStr doubleValue];
MKPointAnnotation *point2 = [[MKPointAnnotation alloc] init];
point2.coordinate = CLLocationCoordinate2DMake(cordinate.latitude, cordinate.longitude);
[self.mapView addAnnotation:point2];
//This is my code for MKAnnotationView
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKPointAnnotation class]]){
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if(!pinView){
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"annotation"];
pinView.calloutOffset = CGPointMake(0, 0);
}
else{
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
What i need to change in the viewForAnnotation method?
For example, you can create subclass of MKPointAnnotation.
#interface SecondAnnotation: MKPointAnnotation
#end
#implementation SecondAnnotation
#end
Add SecondAnnotation to the mapView.
// MKPointAnnotation - 2
...
SecondAnnotation *point2 = [[SecondAnnotation alloc] init];
point2.coordinate = CLLocationCoordinate2DMake(cordinate.latitude,
cordinate.longitude);
[self.mapView addAnnotation:point2];
You can use different MKAnnotationView with the following code.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKPointAnnotation class]]){
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if(!pinView){
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"Annotation"];
pinView.calloutOffset = CGPointMake(0, 0);
}
else{
pinView.annotation = annotation;
}
return pinView;
} else if ([annotation isKindOfClass:[SecondAnnotation class]]){
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if(!pinView){
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"Second"];
pinView.calloutOffset = CGPointMake(0, 0);
}
else{
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Writing the viewForAnnotation as below solved my problem -
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKPointAnnotation class]]){
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if(!pinView){
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"annotation"];
pinView.calloutOffset = CGPointMake(0, 0);
}
else{
pinView.annotation = annotation;
if ([annotation isKindOfClass:[SecondAnnotation class]]) {
pinView.image = [UIImage imageNamed:#"range"];
}
else{
pinView.image = [UIImage imageNamed:#"annotation"];
}
}
return pinView;
}
return nil;
}

custom annotation is not appearing without setting image

I am trying to create custom annotation as each annotation save some data which i need to show on tap of pin. But i need to show default ios pin image. Everything is working fine but pin will only show when i set any image. without setting image it is not showing default ios pin. My code is
CustomAnnotation.h file
#interface CustomAnnotation : NSObject<MKAnnotation>
#property(nonatomic,strong)NSString *title;
#property(nonatomic,strong)NSString *subTitle;
#property(nonatomic)CLLocationCoordinate2D coordinate;
#property(nonatomic,strong) UserDevice *userData;
-(instancetype)initWithUserData:(UserDevice *)userData;
on mapViewC.h
-(void)addMarkersOnMap{
for (UserDevice* userDevice in markersArray) {
CustomAnnotation *point = [[CustomAnnotation alloc]initWithUserData:userDevice];
point.coordinate = CLLocationCoordinate2DMake(userDevice.latitude, userDevice.longitude);
point.userData = userDevice;
point.title = #"dszf";
[mapview addAnnotation:point];
MKMapRect mapRect = [self getZoomingRectOnMap:mapview toFitAllOverlays:YES andAnnotations:YES includeUserLocation:NO];
[mapview setVisibleMapRect:mapRect edgePadding:UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0) animated:YES];
}
}
#pragma mark - MKMapView Delegate methods
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
CustomAnnotation *customAnnotation = annotation;
MKAnnotationView *customAnnotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"annotationViewID"];
if (customAnnotationView == nil){
customAnnotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"annotationViewID"];
}
// customAnnotationView.image = [UIImage imageNamed:#"pin-1"];
customAnnotationView.canShowCallout = true;
customAnnotationView.annotation = customAnnotation;
return customAnnotationView;
}
return nil;
}
Instead of CustomAnnotationView use MKPinAnnotationView in your viewForAnnotation MKMapViewDelegate method
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
CustomAnnotation *customAnnotation = annotation;
MKPinAnnotationView *customAnnotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"annotationViewID"];
if (customAnnotationView == nil){
customAnnotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"annotationViewID"];
}
// customAnnotationView.image = [UIImage imageNamed:#"pin-1"];
customAnnotationView.canShowCallout = true;
customAnnotationView.annotation = customAnnotation;
return customAnnotationView;
}
return nil;
}
Hope this helps
CustomAnnotation *customAnnotation = annotation;
NSString *annotationIdentifier = #"PinViewAnnotation";
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier: annotationIdentifier];
if (pinView ==nil) {
pinView = [[MKPinAnnotationView alloc]initWithAnnotation: customAnnotation reuseIdentifier: annotationIdentifier];
}
pinView.pinColor = MKPinAnnotationColorGreen; // change color
pinView.canShowCallout = YES;
pinView.enabled = YES;
mapView selectAnnotation:pinView animated:YES];

Add Pin Color to MKAnnotation

I have a button on Map which directs to "MyLocation" its hardcore lat n lng. i want to change the pin color. Tried some but not successful. Heres the code.
- (IBAction)btnMylLocation:(UIButton *)sender {
CLLocationCoordinate2D coord = {.latitude = 18.520430, .longitude = 73.856744};
MKCoordinateSpan span = {.latitudeDelta = 0.2, .longitudeDelta = 0.2};
MKCoordinateRegion region = {coord, span};
[self.mapView setRegion:region];
CLLocationCoordinate2D annotationCoord;
annotationCoord.latitude = 18.520430;
annotationCoord.longitude = 73.856744;
self.lblLongitude.text = [NSString stringWithFormat:#"%f ", annotationCoord.latitude];
self.lblLatitude.text = [NSString stringWithFormat:#" %f", annotationCoord.longitude];
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
annotationPoint.title = #"Mindbowser";
annotationPoint.subtitle = #"Pune Headquater's";
[_mapView addAnnotation:annotationPoint];
}
You need to implement the map's delegate method and set the delegate.
- (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]])
{
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.pinColor = MKPinAnnotationColorGreen;
}
else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
In your viewDidLoad() , write the following code
_mapView.delegate = self;
This may help you.
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
MKPinAnnotationView *annotationView = nil;
if(![annotation isKindOfClass:[MKUserLocation class]]){
annotationView=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"pin"];
annotationView.pinColor = MKPinAnnotationColorGreen;
}
return annotationView;
}
Implement the delegate method below and return MKAnnotationView by assigning the pinTintColor it is available from iOS 9.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *annotaionIdentifier=#"annotationIdentifier";
MKPinAnnotationView *aView=(MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:annotaionIdentifier ];
if (aView==nil) {
aView=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:annotaionIdentifier];
aView.pinTintColor = [UIColor yellowColor];//from iOS 9, you can pass in any color you want.
//aView.pinColor = MKPinAnnotationColorPurple //if iOS is less than 9.0
aView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
aView.animatesDrop=TRUE;
aView.canShowCallout = YES;
aView.calloutOffset = CGPointMake(-5, 5);
}
return aView;
}
To change color while adding annotation, check below method.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation
(id<MKAnnotation>)annotation {
static NSString *identifier = #"PinAnnotationIdentifier";
MKPinAnnotationView *pinAnnotation = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(!pinAnnotation) {
pinAnnotation = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
}
pinAnnotation.pinColor = MKPinAnnotationColorGreen; //Color
return pinAnnotation;
}
Use below method for changing color on select and deselect.
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKPinAnnotationView *)view {
view.pinColor = MKPinAnnotationColorRed;
}
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKPinAnnotationView *)view {
view.pinColor = MKPinAnnotationColorGreen;
}

MKAnnotationView images has replaced after zoom or reopen tap

I am parse Json with coordinates and download individual profile image for each annotation view. When I do zoom or move on map I see what images replaced on wrong places. For example I have annotation view with coordinates 111.1111, 111.1111. First time image and coordinate is correct, but after moves/zoom/reopen tab with map I see other annotation view with coordinates 222.222, 222.222 with image which is suitable for 111.111, 111.1111.
(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *identifier = #"SYLocationItem";
if ([annotation isKindOfClass:[SYLocationItem class]]) {
MKAnnotationView *annotationView = (MKAnnotationView *) [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = NO;
SYJabberClient *client = [SYJabberClient sharedClient];
[client retrieveProfileForUserWithEmail:[(SYLocationItem*)annotation email]
withSuccessBlock:^(NSDictionary *dict, NSError *error) {
if (dict) {
UIImage *image = [dict objectForKey:#"imageFile"];
UIImage *displayImage = [UIImage circularScaleNCrop:image
withRect:
CGRectMake(0.0f,0.0f,30.0f,30.0f)];
annotationView.image = displayImage;
}
}];
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
In this code now I get image from local, but if downloading images I have same issue.

I want to plot the MKmapannotation by the photos

Here is my code:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MapLocation *Annotation = annotation;
static NSString *identifier = #"MapLocation";
if ([annotation isKindOfClass:[MapLocation class]]) {
MKPinAnnotationView *annotationViewBus = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
MKPinAnnotationView *annotationViewTaxi = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
MKPinAnnotationView *annotationViewSam = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
MKPinAnnotationView *annotationViewMetro = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
//bus
if (!annotationViewBus ) {
annotationViewBus = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewBus.enabled = YES;
annotationViewBus.canShowCallout = YES;
if (busStatus==YES) {
annotationViewBus.image=[UIImage imageNamed:#"annotationBus.png"];//here we use a nice image instead of the default pins
return annotationViewBus;
}else {
annotationViewBus.annotation = annotation;
}
}
//taxi
if (!annotationViewTaxi ) {
annotationViewTaxi = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewTaxi.enabled = YES;
annotationViewTaxi.canShowCallout = YES;
if (taxiStatus==YES) {
annotationViewTaxi.image=[UIImage imageNamed:#"annotationTaxi.png"];//here we use a nice image instead of the default pins
// return annotationViewTaxi;
}else {
annotationViewTaxi.annotation = annotation;
}
}
//sam
if (!annotationViewSam ) {
annotationViewSam = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewSam.enabled = YES;
annotationViewSam.canShowCallout = YES;
if(samStatus==YES){
annotationViewSam.image=[UIImage imageNamed:#"annotationSam.png"];
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:[Annotation name] forState:UIControlStateNormal];
[rightButton addTarget:self action:#selector(chatButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; //display another view
annotationViewSam.rightCalloutAccessoryView = rightButton;
// return annotationViewSam;
}else {
annotationViewSam.annotation = annotation;
}
}
//metro
if (!annotationViewMetro ) {
annotationViewMetro = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewMetro.enabled = YES;
annotationViewMetro.canShowCallout = YES;
if(metroStatus==YES){
annotationViewMetro.image=[UIImage imageNamed:#"annotationMetro.png"];
}else {
annotationViewMetro.annotation = annotation;
}
//return annotationViewMetro;
}
}
return nil;
}
You have forgotten return (MKAnnotationView *) for each Annotation View type.
Just add return AnnotationView for each type. For example:
//metro
if (!annotationViewMetro ) {
annotationViewMetro = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewMetro.enabled = YES;
annotationViewMetro.canShowCallout = YES;
if(metroStatus==YES){
annotationViewMetro.image=[UIImage imageNamed:#"annotationMetro.png"];
}else {
annotationViewMetro.annotation = annotation;
}
just uncomment this line:
return annotationViewMetro;
}

Resources