iOS Map

iOS Map viewer: MKMapView

  • Create with the Interface Builder, or
  • alloc/init
@property (readonly) id <MKAnnotation> annotations;

Map Annotation

Annotation, like pin annotation, can be added to a map to mark locations on a map

  • MKAnnotation is a protocol containing location & title information
  • Application can add an array of objects implementing MKAnnotation to a map view so it can mark it on a map

Declare an Object implement the MKAnnotation Protocol

@interface MyObject <MKAnnotation>
...
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (readonly) NSString *title;

Implement the MKAnnotation protocol

- (CLLocationCoordinate2D)coordinate
{
  CLLocationCoordinate2D location;
  location.latitude = ...
  location.longitude = ...
  return location;
}

- (NSString *)title
{
  return self.name;
}

To add an array of annotation objects to a map view

[self.mapView addAnnotations:...];

Map Annotation Properties and API

MKAnnotation

@protocol MKAnnotation <NSObject>
@property (readonly) CLLocationCoordinate2D coordinate;
@optional
@property (readonly) NSString *title;
@property (readonly) NSString *subtitle;
@end
typedef {
    CLLocationDegrees latitude;
    CLLocationDegrees longitude;
} CLLocationCoordinate2D;

APIs in adding/removing Map annotation

- (void)addAnnotation:(id <MKAnnotation>)annotation;
- (void)addAnnotations:(NSArray *)annotations;
- (void)removeAnnotation:(id <MKAnnotation>)annotation;
- (void)removeAnnotations:(NSArray *)annotations;

iOS Map Annotation View: MKAnnotationView

When user click on the annotation, an annotation view pops up

  • Create a right and left callout accessor
    - (MKAnnotationView *)mapView:(MKMapView *)sender viewForAnnotation:(id <MKAnnotation>)annotation
    {
      MKAnnotationView *aView = [sender dequeueReusableAnnotationViewWithIdentifier:@"MyAnnotationView"];
    
      if (!aView) {
        aView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"MyAnnotationView"];
        aView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        aView.leftCalloutAccessoryView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,30,30)];
        aView.canShowCallout = YES;
      }
    
      ((UIImageView *)aView.leftCalloutAccessoryView).image = nil;
      aView.annotation = annotation;
    
      return aView;
    }
    

Create and download an thumbnail image for the left accessory

- (void)mapView:(MKMapView *)sender didSelectAnnotationView:(MKAnnotationView *)aView
{
  MyClass o1 = nil;
  UIImageView imageView = nil;
  if ([aView.annotation isKindOfClass:[MyClass class]]) {
    o1 = (MyClass *)aView.annotation;
  }
  if ([aView.leftCalloutAccessoryView isKindOfClass:[UIImageView class]]) {
    imageView = (UIImageView *)aView.leftCalloutAccessoryView;
  }
  if (o1 && imageView)
  {
    NSString *thumbnailURL = o1.thumbnailURL;
    if (thumbnailURL) {
      dispatch_queue_t downloader = dispatch_queue_create("image downloader", NULL);
      dispatch_async(downloader, ^{
	   UIImage *image = [UIImage imageWithData:[FlickrFetcher imageDataForPhotoWithURLString:thumbnailURL]];
	   dispatch_async(dispatch_get_main_queue(), ^{
		imageView.image = image;
	   });
      });
      dispatch_release(downloader);
    }
  }
}

Delegate handle the tapping of the annotation view accessor

- (void)mapView:(MKMapView *)sender annotationView:(MKAnnotationView *)aView calloutAccessoryControlTapped:(UIControl *)control
{
...
}

Annotation Properties

@property(retain)id<MKAnnotation>annotation;
@property(retain)UIImage*image;
@property(retain)UIView*leftCalloutAccessoryView;
@property(retain)UIView*rightCalloutAccessoryView;
@propertyBOOLenabled;
@propertyCGPointcenterOffset;
@propertyBOOLdraggable;
- (void)mapView:(MKMapView *)sender
               annotationView:(MKAnnotationView *)aView
calloutAccessoryControlTapped:(UIControl *)control;
aView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

Delegate for MKMapView

Call when display a map view

- (void)mapView:(MKMapView *)sender regionDidChangeAnimated:(BOOL)animated;

The map rectangle

@property(readonly)MKMapRectvisibleRect;

Only add annotations that is visible in the map

MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
if (MKMapRectContainsPoint(mapView.visibleRect, annotationPoint))
{ ... }