Developer Area

Changeset 677

Show
Ignore:
Timestamp:
01/20/10 12:57:19 (8 weeks ago)
Author:
henri
Message:

Significant update to location controller. Map now responds better to location updates and zooms smoothly with feedback when switching locations.

Location:
apps/iphone/my.tel/trunk/Classes
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • apps/iphone/my.tel/trunk/Classes/LocationViewController.h

    r593 r677  
    3939- (void)resetData; 
    4040- (void)recenterMap; 
     41- (void)moveFromLocation:(CLLocation *)fromLoc toLocation:(CLLocation *)toLoc accuracy:(CLLocationDistance)accuracy animated:(BOOL)animated; 
    4142- (void)updateUILocationWithJson:(NSDictionary *)parsedJson; 
    4243- (void)getLocation; 
  • apps/iphone/my.tel/trunk/Classes/LocationViewController.m

    r670 r677  
    99#import "LocationViewController.h" 
    1010 
     11#define kKMapDefaultZoomWidthInMeters 1000.0 
     12 
    1113@interface LocationViewController (PrivateMethods) 
    1214- (void)setDidPreload:(BOOL)preload; 
     15- (void)animateZoomIntoRegionUsingNSValue:(NSValue *)aValue; 
    1316@end 
    1417 
     
    3437        [theC resetData]; 
    3538        if (preload) { 
    36                 theC.view.hidden = NO;          // Force preload of the view 
    37 //              theC.theMap.hidden = NO;        // Enable this to also force map preload. Beware of needless data access! 
     39                theC.view.hidden = NO;          // Force preload of the view and map 
    3840                [theC getLocation]; 
    3941        } 
     
    5153- (void)viewDidLoad { 
    5254    [super viewDidLoad]; 
    53         theMap.delegate = self; 
    5455        [MyCLController sharedInstance].delegate = self; 
     56        self.theMap.delegate = self; 
     57        self.theMap.showsUserLocation = YES; 
    5558} 
    5659 
     
    5962        // Don't get the data if we preloaded 
    6063        if (didPreload) { 
    61                 didPreload = NO; 
    6264        } else { 
    6365                [self getLocation]; 
     
    6769- (void)viewDidAppear:(BOOL)animated { 
    6870        [super viewDidAppear:animated]; 
    69         self.theMap.showsUserLocation = YES; 
     71        // Only if we preloaded: 
     72        // Recenter to either span all the annotations, or just the user location 
     73        if (didPreload) { 
     74                didPreload = NO; 
     75                if (self.markerTel != nil) { 
     76                        [self recenterMap]; 
     77                } else { 
     78                        [self didPressCenterGps:nil]; 
     79                } 
     80        } 
    7081} 
    7182 
     
    89100        telLocIsAvailable = NO; 
    90101        buttonDeleteLoc.enabled = telLocIsAvailable; 
     102        self.markerTel = nil; 
    91103} 
    92104 
    93105- (void)recenterMap { 
    94106        // Center and zoom the map so it has all the annotations in it 
    95         NSArray *coordinates = [self.theMap valueForKeyPath:@"annotations.coordinate"]; 
     107         
     108        // Special case if there's only one annotation 
     109        if ([theMap.annotations count] == 1) { 
     110                NSObject <MKAnnotation> *ann = [theMap.annotations objectAtIndex:0]; 
     111                MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(ann.coordinate, kKMapDefaultZoomWidthInMeters, kKMapDefaultZoomWidthInMeters); 
     112                [theMap setRegion:[theMap regionThatFits:region] animated:YES]; 
     113                return; 
     114        } 
     115         
    96116        CLLocationCoordinate2D maxCoord = {-90.0f, -180.0f}; 
    97117        CLLocationCoordinate2D minCoord = {90.0f, 180.0f}; 
    98         for (NSValue *value in coordinates) { 
    99                 CLLocationCoordinate2D coord = {0.0f, 0.0f}; 
    100                 [value getValue:&coord]; 
     118        NSObject <MKAnnotation> *ann; 
     119        for (ann in self.theMap.annotations) { 
     120                CLLocationCoordinate2D coord = ann.coordinate; 
    101121                if(coord.longitude > maxCoord.longitude) { 
    102122                        maxCoord.longitude = coord.longitude; 
     
    115135        region.center.longitude = (minCoord.longitude + maxCoord.longitude) / 2.0; 
    116136        region.center.latitude = (minCoord.latitude + maxCoord.latitude) / 2.0; 
     137        region.span.latitudeDelta = 1.3 * (maxCoord.latitude - minCoord.latitude);              // make the region 30% bigger than necessary 
    117138        region.span.longitudeDelta = 1.3 * (maxCoord.longitude - minCoord.longitude);   // make the region 30% bigger than necessary 
    118         region.span.latitudeDelta = 1.3 * (maxCoord.latitude - minCoord.latitude);              // make the region 30% bigger than necessary 
     139        if ((region.span.latitudeDelta == 0) && (region.span.longitudeDelta == 0)) 
     140                region.span.latitudeDelta = region.span.longitudeDelta = kKMapDefaultZoomWidthInMeters; 
    119141        [theMap setRegion:[theMap regionThatFits:region] animated:YES]; 
    120142} 
    121143 
     144- (void)moveFromLocation:(CLLocation *)fromLoc toLocation:(CLLocation *)toLoc accuracy:(CLLocationDistance)accuracy animated:(BOOL)animated { 
     145        // First zoom out until the new loc is visible, then rezoom back in 
     146         
     147        CLLocationDegrees minLat, maxLat, minLong, maxLong; 
     148        minLat = MIN(fromLoc.coordinate.latitude, toLoc.coordinate.latitude); 
     149        maxLat = MAX(fromLoc.coordinate.latitude, toLoc.coordinate.latitude); 
     150        minLong = MIN(fromLoc.coordinate.longitude, toLoc.coordinate.longitude); 
     151        maxLong = MAX(fromLoc.coordinate.longitude, toLoc.coordinate.longitude); 
     152         
     153        MKCoordinateRegion region = {{0.0f, 0.0f}, {0.0f, 0.0f}}; 
     154        region.center.longitude = (minLong + maxLong) / 2.0; 
     155        region.center.latitude = (minLat + maxLat) / 2.0; 
     156        region.span.longitudeDelta = 1.2 * (maxLong - minLong);         // make the region 20% bigger than necessary 
     157        region.span.latitudeDelta = 1.2 * (maxLat - minLat);            // make the region 20% bigger than necessary 
     158        [theMap setRegion:[theMap regionThatFits:region] animated:animated]; 
     159 
     160        // Now we've got both items in, we zoom back down into the other loc 
     161        region = MKCoordinateRegionMakeWithDistance(toLoc.coordinate, accuracy, accuracy); 
     162        if (animated) { 
     163                NSValue *regionAsValue = [NSValue valueWithBytes:&region objCType:@encode(MKCoordinateRegion)]; 
     164                [self performSelector:@selector(animateZoomIntoRegionUsingNSValue:) withObject:regionAsValue afterDelay:0.1f]; 
     165//              [self performSelectorOnMainThread:@selector(animateZoomIntoRegionUsingNSValue:) withObject:regionAsValue waitUntilDone:NO]; 
     166        } else { 
     167                [theMap setRegion:[theMap regionThatFits:region] animated:NO]; 
     168        } 
     169 
     170} 
     171 
     172- (void)animateZoomIntoRegionUsingNSValue:(NSValue *)aValue { 
     173        // wrapper to pass in a MKCoordinateRegion as an object so we can run it asynchronously 
     174        MKCoordinateRegion region; 
     175        [aValue getValue:&region]; 
     176        [theMap setRegion:[theMap regionThatFits:region] animated:YES]; 
     177} 
     178 
    122179#pragma mark ------ MKMapViewDelegate Methods 
    123180 
    124 - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views { 
    125         MKAnnotationView *aV; 
    126         for (aV in views) { 
    127                 if (aV.annotation == theMap.userLocation) { 
    128                         [theMap setCenterCoordinate:theMap.userLocation.location.coordinate animated:YES]; 
    129                         // zoom in (even if it's updating) 
    130                         CLLocation *theLoc = [MyCLController sharedInstance].myCurrentLoc; 
    131                         CLLocationDistance radiusAccuracy = 1000; 
    132                         if (theLoc.horizontalAccuracy > 0.9 * radiusAccuracy) 
    133                                 radiusAccuracy = theLoc.horizontalAccuracy / 0.9; 
    134                         MKCoordinateRegion aR = MKCoordinateRegionMakeWithDistance(theMap.userLocation.location.coordinate, radiusAccuracy, radiusAccuracy); 
    135                         [theMap setRegion:[theMap regionThatFits:aR] animated:YES]; 
    136                 } 
    137         } 
    138 } 
     181//- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views { 
     182//      MKAnnotationView *aV; 
     183//      for (aV in views) { 
     184//              if (aV.annotation == mapView.userLocation) { 
     185//              } 
     186//      } 
     187//} 
    139188 
    140189#pragma mark ---- MyCLController delegate methods ---- 
     
    143192        if (aLoc) { 
    144193                gpsLocIsAvailable = YES; 
     194                self.theMap.showsUserLocation = YES; 
    145195        } else { 
    146196                gpsLocIsAvailable = NO; 
     197                self.theMap.showsUserLocation = NO; 
    147198        } 
    148199} 
     
    196247 
    197248- (IBAction)didPressCenterGps:(id)sender { 
    198         [self.theMap setCenterCoordinate:[[[MyCLController sharedInstance] myCurrentLoc] coordinate]]; 
     249        // Move to current loc, and zoom to 500 meters or the current accuracy of gps, whichever is higher 
     250        CLLocation *currentCenter = [[CLLocation alloc] initWithCoordinate:theMap.centerCoordinate 
     251                                                                                                                          altitude:0.0 
     252                                                                                                        horizontalAccuracy:10.0 
     253                                                                                                          verticalAccuracy:10.0 
     254                                                                                                                         timestamp:[NSDate date]]; 
     255        CLLocation *theLoc = theMap.userLocation.location; 
     256        CLLocationDistance radiusAccuracy = kKMapDefaultZoomWidthInMeters; 
     257        if (theLoc.horizontalAccuracy > 0.9 * radiusAccuracy) 
     258                radiusAccuracy = theLoc.horizontalAccuracy / 0.9; 
     259        [self moveFromLocation:currentCenter toLocation:[MyCLController sharedInstance].myCurrentLoc accuracy:radiusAccuracy animated:YES]; 
     260        [currentCenter release]; 
    199261} 
    200262 
    201263- (IBAction)didPressCenterTel:(id)sender { 
    202         [self.theMap setCenterCoordinate:self.markerTel.coordinate]; 
     264        CLLocation *currentCenter = [[CLLocation alloc] initWithCoordinate:theMap.centerCoordinate 
     265                                                                                                                          altitude:0.0 
     266                                                                                                        horizontalAccuracy:10.0 
     267                                                                                                          verticalAccuracy:10.0 
     268                                                                                                                         timestamp:[NSDate date]]; 
     269        CLLocation *newCenter = [[CLLocation alloc] initWithCoordinate:self.markerTel.coordinate 
     270                                                                                                                  altitude:0.0 
     271                                                                                                horizontalAccuracy:10.0 
     272                                                                                                  verticalAccuracy:10.0 
     273                                                                                                                 timestamp:[NSDate date]]; 
     274        [self moveFromLocation:currentCenter toLocation:newCenter accuracy:kKMapDefaultZoomWidthInMeters animated:YES]; 
     275        [currentCenter release]; 
     276        [newCenter release]; 
    203277} 
    204278 
     
    226300- (IBAction)gpsSwitchToggled:(UISwitch *)sender { 
    227301        // Use if there's a switch to turn on or off the GPS 
     302        self.theMap.showsUserLocation = sender.on; 
    228303        if (sender.on) { 
    229304                [[MyCLController sharedInstance].locationManager startUpdatingLocation]; 
Telnic
Search This Site
Partners
Neustar
ICANN
Main site | WHOIS | Sell .tel | FAQ | Archived Site | About Telnic | Contact Us