Maps on the
                                  iPhone
                                Using MapKit for Fun and Profit




W...
Add A MKMapView




Wednesday, September 30, 2009                     2
Tweak Parameters


                                Show the blue breathing dot




                                       ...
And Bada-Boom
                                  A Map App




Wednesday, September 30, 2009                   4
But we want more,
                                like the breathing
                                     Blue Dot




Wed...
Where we are
                                       Headed
                                ‘Right’ Action - Details



   ...
Stuff To Do
                  • View Based Project
                  • Parse XML from USGS
                  • Create Eart...
View Based Project
              Connect the
            MapView to our VC
Wednesday, September 30, 2009                  ...
Parse XML
              NSOperationQueue


             operation
                                NSOperation
            ...
NSOperationQueue


                operation
                                  NSOperation
                 thread




   ...
EarthquakeParser


                           initWithContentsOfURL:




                                                 ...
NSXMLParser Kick-off
  - (BOOL)parseForData {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [UIAppli...
Create Earthquakes
                                                    EarthquakeParser




                              ...
Entry Element starts
                          and Earthquake
 - (void)parser:(NSXMLParser *)parser didStartElement:(NSStr...
EarthquakeParser                     Back to the Main
                                                                    ...
Ending Element Pushes
                       Earthquake




                                                              ...
MapQuakesVC holds the
                     Earthquakes




                                                         Store ...
EarthquakeParser                        Back to the Main
                                                                 ...
Back to the Main Thread
                          Again




                                                              ...
Display Earthquakes as
                        Annotations




                                            Add Annotations...
Remove Old Annotations
- (void)displayEarthquakes {




                                                                  ...
Find Visible Quakes
                          Sorted by Magnitude
- (void)displayEarthquakes {




                       ...
Limit Earthquakes to
                                  100
- (void)displayEarthquakes {




                              ...
Find and Display
                                  Earthquakes
- (void)displayEarthquakes {




                          ...
Remove old Earthquake
                       Annotations




                                                             ...
Filter Visible
                                Earthquakes
  - (NSArray *)sortAndFilterEarthquakes {




                 ...
Sort Earthquakes
  - (NSArray *)sortAndFilterEarthquakes {




                                                           ...
Provide Annotation Views
                                       EarthquakeParserDelegate
                                 ...
Return nil for user




                                                                                  Provide Annotati...
Provide Annotation Views
                 Reuse Annotation Views
 - (MKAnnotationView *)mapView:(MKMapView *)mapView
     ...
Create if no re-useable




                                                                                  Provide Anno...
Provide Annotation Views
                                Configure View
 - (MKAnnotationView *)mapView:(MKMapView *)mapView...
Custom




                                                     Provide Annotation Views
                                 ...
Configure the




                                                                         Provide Annotation Views
       ...
Provide Annotation Views
                                Shape Layer
  - (void) addBreathingLayer {
    self.circleLayer =...
Provide Annotation Views
                          Breathing Animation
  - (void) addBreathingLayer {
    self.circleLayer...
Selection Starts




                                                                         Provide Annotation Views
   ...
De-Selection Stops




                                                                         Provide Annotation Views
 ...
Selected Animation




                                                Provide Annotation Views
Wednesday, September 30, 2...
‘Right’ Detail




                                                   Respond To Events
                                ‘L...
Open The Web Page




                                                                                        Respond To E...
Where To Now?
                   • Your data will likely have more
                     interesting selection criteria, ex...
Summary


                   • Filtering your Annotations is important
                     if you have lots of data
     ...
Thanks!
                                Pragmatic iPhone Studio




Wednesday, September 30, 2009                         ...
Upcoming SlideShare
Loading in...5
×

360iDev MapKit Presentation - Denver 2009

10,196

Published on

The Presentation I gave at 360iDev in Denver 2009

Published in: Education
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
10,196
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
114
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

360iDev MapKit Presentation - Denver 2009

  1. 1. Maps on the iPhone Using MapKit for Fun and Profit Wednesday, September 30, 2009 1
  2. 2. Add A MKMapView Wednesday, September 30, 2009 2
  3. 3. Tweak Parameters Show the blue breathing dot Then Build and Go... Wednesday, September 30, 2009 3
  4. 4. And Bada-Boom A Map App Wednesday, September 30, 2009 4
  5. 5. But we want more, like the breathing Blue Dot Wednesday, September 30, 2009 5
  6. 6. Where we are Headed ‘Right’ Action - Details ‘Left’ Action - Shake Map Animated ‘Breathing’ Wednesday, September 30, 2009 6
  7. 7. Stuff To Do • View Based Project • Parse XML from USGS • Create Earthquakes • Store Earthquakes • Add Annotations • Provide Annotation Views • Respond to Events Wednesday, September 30, 2009 7
  8. 8. View Based Project Connect the MapView to our VC Wednesday, September 30, 2009 8
  9. 9. Parse XML NSOperationQueue operation NSOperation thread parseForData: addOperation: Parse XML EarthquakeParser initWithContentsOfURL: parse invokeOnMainThread: didStartElement: foundCharcters: didEndElement: NSXMLParser event loop addEarthquake: parserFinished EarthquakeParserDelegate (MapQuakesViewController) Don’t block the main event thread! Wednesday, September 30, 2009 9
  10. 10. NSOperationQueue operation NSOperation thread Parse XML parseForData: addOperation: EarthquakeParser Kick Off The Parse parseForData: is on an alternate thread, won’t block event thread while downloading the XML Wednesday, September 30, 2009 10
  11. 11. EarthquakeParser initWithContentsOfURL: Parse XML parse NSXMLParser Parse XML on the Each XML Event comes to the parser’s delegate on the alternate thread alternate thread Wednesday, September 30, 2009 11
  12. 12. NSXMLParser Kick-off - (BOOL)parseForData { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; NSURL *url = [NSURL URLWithString:feedURLString]; Parse XML BOOL success = NO; NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url]; [parser setDelegate:self]; [parser setShouldProcessNamespaces:NO]; [parser setShouldReportNamespacePrefixes:NO]; [parser setShouldResolveExternalEntities:NO]; success = [parser parse]; NSError *parseError = [parser parserError]; if (parseError) { ! NSLog(@"parse error = %@", parseError); } [parser release]; [pool drain]; return success; } Wednesday, September 30, 2009 12
  13. 13. Create Earthquakes EarthquakeParser didStartElement: foundCharcters: didEndElement: NSXMLParser Parse XML on the Each XML Event comes to the parser’s delegate on the alternate thread alternate thread Wednesday, September 30, 2009 13
  14. 14. Entry Element starts and Earthquake - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName Create Earthquakes attributes:(NSDictionary *)attributeDict { if(nil != qName) { elementName = qName; // swap for the qName if we have a name space } if ([elementName isEqualToString:@"entry"]) { self.currentEarthquake = [[[Earthquake alloc] init] autorelease]; } else if([elementName isEqualToString:@"link"]) { // ignore the related content and just grab the alternate if ([[attributeDict valueForKey:@"rel"] isEqualToString:@"alternate"]) { NSString *link = [attributeDict valueForKey:@"href"]; self.currentEarthquake.detailsURL = [NSString stringWithFormat:@"http://earthquake.usgs.gov/%@", link]; } } else if([elementName isEqualToString:@"title"] || [elementName isEqualToString:@"updated"] || [elementName isEqualToString:@"id"] || [elementName isEqualToString:@"georss:point"] || [elementName isEqualToString:@"georss:elev"]) { self.propertyValue = [NSMutableString string]; } else { self.propertyValue = nil; } } Wednesday, September 30, 2009 14
  15. 15. EarthquakeParser Back to the Main Thread Store Earthquakes invokeOnMainThread: event loop addEarthquake: EarthquakeParserDelegate Let the main thread know an earthquake was (MapQuakesViewController) found by pushing the addEarthquake: and parserFinished methods onto the main thread Wednesday, September 30, 2009 15
  16. 16. Ending Element Pushes Earthquake Store Earthquakes - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { ... } else if([elementName isEqualToString:@"entry"]) { Earthquake *quake = self.currentEarthquake; self.currentEarthquake = nil; [(id)[self delegate] performSelectorOnMainThread:@selector(addEarthquake:) withObject:quake waitUntilDone:NO]; } } Wednesday, September 30, 2009 16
  17. 17. MapQuakesVC holds the Earthquakes Store Earthquakes - (void)addEarthquake:(Earthquake *)earthquake { [self.earthquakes addObject:earthquake]; } Wednesday, September 30, 2009 17
  18. 18. EarthquakeParser Back to the Main Thread Add Annotations invokeOnMainThread: event loop parserFinished EarthquakeParserDelegate Once all the XML is parsed we tell the delegate (MapQuakesViewController) which displays the earthquakes in the form of an annotation. Wednesday, September 30, 2009 18
  19. 19. Back to the Main Thread Again Add Annotations - (void)parserDidEndDocument:(NSXMLParser *)parser { [(id)[self delegate] performSelectorOnMainThread:@selector(parserFinished) withObject:nil waitUntilDone:NO]; [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; [self autorelease]; } Wednesday, September 30, 2009 19
  20. 20. Display Earthquakes as Annotations Add Annotations - (void)parserFinished { [self displayEarthquakes]; } Wednesday, September 30, 2009 20
  21. 21. Remove Old Annotations - (void)displayEarthquakes { Add Annotations [self removeAnnotations]; NSArray *visibleQuakes = [self sortAndFilterEarthquakes]; // limit the numer to 100 if(visibleQuakes.count > 100) { // remove the earthquakes from the top of the // list until we are down to 100 NSUInteger removeCount = visibleQuakes.count - 100; NSRange keepers = {removeCount, 100}; // location and length visibleQuakes = [visibleQuakes subarrayWithRange:keepers]; } for(Earthquake *earthquake in visibleQuakes) { EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation annotationWithEarthquake:earthquake]; [self.mapView addAnnotation:eqAnn]; } } Wednesday, September 30, 2009 21
  22. 22. Find Visible Quakes Sorted by Magnitude - (void)displayEarthquakes { Add Annotations [self removeAnnotations]; NSArray *visibleQuakes = [self sortAndFilterEarthquakes]; // limit the numer to 100 if(visibleQuakes.count > 100) { // remove the earthquakes from the top of the // list until we are down to 100 NSUInteger removeCount = visibleQuakes.count - 100; NSRange keepers = {removeCount, 100}; // location and length visibleQuakes = [visibleQuakes subarrayWithRange:keepers]; } for(Earthquake *earthquake in visibleQuakes) { EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation annotationWithEarthquake:earthquake]; [self.mapView addAnnotation:eqAnn]; } } Wednesday, September 30, 2009 22
  23. 23. Limit Earthquakes to 100 - (void)displayEarthquakes { Add Annotations [self removeAnnotations]; NSArray *visibleQuakes = [self sortAndFilterEarthquakes]; // limit the numer to 100 if(visibleQuakes.count > 100) { // remove the earthquakes from the top of the // list until we are down to 100 NSUInteger removeCount = visibleQuakes.count - 100; NSRange keepers = {removeCount, 100}; // location and length visibleQuakes = [visibleQuakes subarrayWithRange:keepers]; } for(Earthquake *earthquake in visibleQuakes) { EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation annotationWithEarthquake:earthquake]; [self.mapView addAnnotation:eqAnn]; } } Wednesday, September 30, 2009 23
  24. 24. Find and Display Earthquakes - (void)displayEarthquakes { Add Annotations [self removeAnnotations]; NSArray *visibleQuakes = [self sortAndFilterEarthquakes]; // limit the numer to 100 if(visibleQuakes.count > 100) { // remove the earthquakes from the top of the // list until we are down to 100 NSUInteger removeCount = visibleQuakes.count - 100; NSRange keepers = {removeCount, 100}; // location and length visibleQuakes = [visibleQuakes subarrayWithRange:keepers]; } for(Earthquake *earthquake in visibleQuakes) { EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation annotationWithEarthquake:earthquake]; [self.mapView addAnnotation:eqAnn]; } } Wednesday, September 30, 2009 24
  25. 25. Remove old Earthquake Annotations Add Annotations - (void) removeAnnotations { // remove the old annotations but // don't modify the array while iterating NSArray *annotationsCopy = [self.mapView.annotations copy]; for(id annotation in annotationsCopy) { if([[annotation class] isSubclassOfClass:[EarthquakeAnnotation class]]) { [self.mapView removeAnnotation:annotation]; } } [annotationsCopy release]; } Wednesday, September 30, 2009 25
  26. 26. Filter Visible Earthquakes - (NSArray *)sortAndFilterEarthquakes { Add Annotations // find the visible earthquakes MKCoordinateRegion region = [self.mapView region]; LocationBoundingBox bbox = LocationBoundingBoxMake(region.center, region.span); NSPredicate *latPred = [NSPredicate predicateWithFormat: @"latitude BETWEEN {%@, %@}", [NSNumber numberWithFloat:bbox.min.latitude], [NSNumber numberWithFloat:bbox.max.latitude]]; NSPredicate *lonPred = [NSPredicate predicateWithFormat: @"longitude BETWEEN {%@, %@}", [NSNumber numberWithFloat:bbox.min.longitude], [NSNumber numberWithFloat:bbox.max.longitude]]; NSArray *predicates = [NSArray arrayWithObjects:latPred, lonPred, nil]; NSPredicate *locationPred = [NSCompoundPredicate andPredicateWithSubpredicates:predicates]; NSArray *quakes = [self.earthquakes filteredArrayUsingPredicate:locationPred]; NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"magnitude" ascending:YES]; NSArray *descriptors = [NSArray arrayWithObject:descriptor]; NSArray *sortedEarthquakes = [quakes sortedArrayUsingDescriptors:descriptors]; [descriptor release]; return sortedEarthquakes; } Wednesday, September 30, 2009 26
  27. 27. Sort Earthquakes - (NSArray *)sortAndFilterEarthquakes { Add Annotations // find the visible earthquakes MKCoordinateRegion region = [self.mapView region]; LocationBoundingBox bbox = LocationBoundingBoxMake(region.center, region.span); NSPredicate *latPred = [NSPredicate predicateWithFormat: @"latitude BETWEEN {%@, %@}", [NSNumber numberWithFloat:bbox.min.latitude], [NSNumber numberWithFloat:bbox.max.latitude]]; NSPredicate *lonPred = [NSPredicate predicateWithFormat: @"longitude BETWEEN {%@, %@}", [NSNumber numberWithFloat:bbox.min.longitude], [NSNumber numberWithFloat:bbox.max.longitude]]; NSArray *predicates = [NSArray arrayWithObjects:latPred, lonPred, nil]; NSPredicate *locationPred = [NSCompoundPredicate andPredicateWithSubpredicates:predicates]; NSArray *quakes = [self.earthquakes filteredArrayUsingPredicate:locationPred]; NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"magnitude" ascending:YES]; NSArray *descriptors = [NSArray arrayWithObject:descriptor]; NSArray *sortedEarthquakes = [quakes sortedArrayUsingDescriptors:descriptors]; [descriptor release]; return sortedEarthquakes; } Wednesday, September 30, 2009 27
  28. 28. Provide Annotation Views EarthquakeParserDelegate (MapQuakesViewController) addAnnotation: viewForAnnotation: MKMapViewDelegate (MapQuakesViewController) delegate Provides Annotation View Wednesday, September 30, 2009 28
  29. 29. Return nil for user Provide Annotation Views location - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *view = nil; if(annotation != mapView.userLocation) { !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation; !! view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"]; !! if(nil == view) { view = [[[EarthquakeAnnotationView alloc] initWithAnnotation:eqAnn reuseIdentifier:@"earthquakeLoc"] autorelease]; !! } view.annotation = annotation; [view setCanShowCallout:YES]; UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; [view setRightCalloutAccessoryView:button]; } return view; } Wednesday, September 30, 2009 29
  30. 30. Provide Annotation Views Reuse Annotation Views - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *view = nil; if(annotation != mapView.userLocation) { !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation; !! view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"]; !! if(nil == view) { view = [[[EarthquakeAnnotationView alloc] initWithAnnotation:eqAnn reuseIdentifier:@"earthquakeLoc"] autorelease]; !! } view.annotation = annotation; [view setCanShowCallout:YES]; UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; [view setRightCalloutAccessoryView:button]; } return view; } Wednesday, September 30, 2009 30
  31. 31. Create if no re-useable Provide Annotation Views views exist - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *view = nil; if(annotation != mapView.userLocation) { !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation; !! view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"]; !! if(nil == view) { view = [[[EarthquakeAnnotationView alloc] initWithAnnotation:eqAnn reuseIdentifier:@"earthquakeLoc"] autorelease]; !! } view.annotation = annotation; [view setCanShowCallout:YES]; UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; [view setRightCalloutAccessoryView:button]; } return view; } Wednesday, September 30, 2009 31
  32. 32. Provide Annotation Views Configure View - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *view = nil; if(annotation != mapView.userLocation) { !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation; !! view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"]; !! if(nil == view) { view = [[[EarthquakeAnnotationView alloc] initWithAnnotation:eqAnn reuseIdentifier:@"earthquakeLoc"] autorelease]; !! } view.annotation = annotation; [view setCanShowCallout:YES]; UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; [view setRightCalloutAccessoryView:button]; } return view; } Wednesday, September 30, 2009 32
  33. 33. Custom Provide Annotation Views MKAnnotationView Subclass EarthquakeAnnotationView Wednesday, September 30, 2009 33
  34. 34. Configure the Provide Annotation Views Annotation View - (void)setAnnotation:annotation { [super setAnnotation:annotation]; [self.layer.sublayers makeObjectsPerformSelector: @selector(removeFromSuperlayer)]; self.frame = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); self.earthquake = [(EarthquakeAnnotation *)annotation earthquake]; [self addBreathingLayer]; [self addDarkCircleLayer]; } Wednesday, September 30, 2009 34
  35. 35. Provide Annotation Views Shape Layer - (void) addBreathingLayer { self.circleLayer = [CAShapeLayer layer]; CGColorRef color = [self newFillColor]; self.circleLayer.fillColor = color; CGColorRelease(color); color = [self newStrokeColor]; self.circleLayer.strokeColor = color; CGColorRelease(color); self.circleLayer.lineWidth = 1.0f; CGMutablePathRef path = CGPathCreateMutable(); CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); self.circleLayer.frame = square; CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; pathAnimation.duration = 1.5f; pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; pathAnimation.repeatCount = 1E100f; pathAnimation.autoreverses = YES; self.circleLayer.actions = [NSDictionary dictionaryWithObject:pathAnimation forKey:@"path"]; [self.layer addSublayer:self.circleLayer]; } Wednesday, September 30, 2009 35
  36. 36. Provide Annotation Views Breathing Animation - (void) addBreathingLayer { self.circleLayer = [CAShapeLayer layer]; CGColorRef color = [self newFillColor]; self.circleLayer.fillColor = color; CGColorRelease(color); color = [self newStrokeColor]; self.circleLayer.strokeColor = color; CGColorRelease(color); self.circleLayer.lineWidth = 1.0f; CGMutablePathRef path = CGPathCreateMutable(); CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); self.circleLayer.frame = square; CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; pathAnimation.duration = 1.5f; pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; pathAnimation.repeatCount = 1E100f; pathAnimation.autoreverses = YES; self.circleLayer.actions = [NSDictionary dictionaryWithObject:pathAnimation forKey:@"path"]; [self.layer addSublayer:self.circleLayer]; } Wednesday, September 30, 2009 36
  37. 37. Selection Starts Provide Annotation Views Animation - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; if(YES == selected) { // animate the bottom shape's path CGRect square = CGRectMake(16.0f, 16.0f, 16.0f, 16.0f); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); EarthquakeParser *parser = [EarthquakeParser earthquakeParser]; parser.delegate = self; [parser getShakeMapForEarthquake:self.earthquake]; } else { [CATransaction begin]; [CATransaction setDisableActions:YES]; CGMutablePathRef path = CGPathCreateMutable(); CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); [CATransaction commit]; } } Wednesday, September 30, 2009 37
  38. 38. De-Selection Stops Provide Annotation Views Animation - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; if(YES == selected) { // animate the bottom shape's path CGRect square = CGRectMake(16.0f, 16.0f, 16.0f, 16.0f); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); EarthquakeParser *parser = [EarthquakeParser earthquakeParser]; parser.delegate = self; [parser getShakeMapForEarthquake:self.earthquake]; } else { [CATransaction begin]; [CATransaction setDisableActions:YES]; CGMutablePathRef path = CGPathCreateMutable(); CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); [CATransaction commit]; } } Wednesday, September 30, 2009 38
  39. 39. Selected Animation Provide Annotation Views Wednesday, September 30, 2009 39
  40. 40. ‘Right’ Detail Respond To Events ‘Left’ Shake Map Wednesday, September 30, 2009 40
  41. 41. Open The Web Page Respond To Events - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { NSURL *url = nil; EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation *)[view annotation]; if(view.rightCalloutAccessoryView == control) { NSString *urlString = [eqAnn.earthquake.detailsURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; url = [NSURL URLWithString:urlString]; } else { NSString *urlString = [eqAnn.earthquake.shakeMapURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; url = [NSURL URLWithString:urlString]; } [[UIApplication sharedApplication] openURL:url]; } Wednesday, September 30, 2009 41
  42. 42. Where To Now? • Your data will likely have more interesting selection criteria, exploit it • The ‘detail’ from right and left buttons can do lots more interesting stuff • USGS Provides KML files for shake maps • Use Core Animation in the right or left buttons Wednesday, September 30, 2009 42
  43. 43. Summary • Filtering your Annotations is important if you have lots of data • It’s easy to build your own custom annotation views and add Core Animation to them Wednesday, September 30, 2009 43
  44. 44. Thanks! Pragmatic iPhone Studio Wednesday, September 30, 2009 44
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×