开发者

Detecting when a user scrolls MKMapView a certain distance?

I want to determine if a user has scrolled more than a certain percentage of the map then disable centering of the map from the user location (similar to how the Maps app works).

I'm not sure which methods to make use of.

I think it woul开发者_开发知识库d be straightforward to create a rectangle and see if the rectangle contains the current center point, however I have to target IOS 3, so I can't make use of many of the newer Mapkit apis.

I've tried futzing with CLLocation, and using distanceFrom, between the current mapcenter, and the users location, but I'm trying to figure out if that distance is a certain percentage.


I personally find it more helpful when someone can post a snippet of code versus general prose about how one might go about this. Here's what I came up with- roughly hacked out to simply better answer this question:

In a header file I have:

#define SCROLL_UPDATE_DISTANCE          80.00

and in my view (that is both a delegate for CLLocationManagerDelegate, MKMapViewDelegate):

// this method is called when the map region changes as a delegate of MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    NSLog(@"regionDidChangeAnimated");
    MKCoordinateRegion mapRegion;   
    // set the center of the map region to the now updated map view center
    mapRegion.center = mapView.centerCoordinate;

    mapRegion.span.latitudeDelta = 0.3; // you likely don't need these... just kinda hacked this out
    mapRegion.span.longitudeDelta = 0.3;

    // get the lat & lng of the map region
    double lat = mapRegion.center.latitude;
    double lng = mapRegion.center.longitude;

    // note: I have a variable I have saved called lastLocationCoordinate. It is of type
    // CLLocationCoordinate2D and I initially set it in the didUpdateUserLocation
    // delegate method. I also update it again when this function is called
    // so I always have the last mapRegion center point to compare the present one with 
    CLLocation *before = [[CLLocation alloc] initWithLatitude:lastLocationCoordinate.latitude longitude:lastLocationCoordinate.longitude];
    CLLocation *now = [[CLLocation alloc] initWithLatitude:lat longitude:lng];

    CLLocationDistance distance = ([before distanceFromLocation:now]) * 0.000621371192;
    [before release];
    [now release];

    NSLog(@"Scrolled distance: %@", [NSString stringWithFormat:@"%.02f", distance]);

    if( distance > SCROLL_UPDATE_DISTANCE )
    {
        // do something awesome
    }

    // resave the last location center for the next map move event
    lastLocationCoordinate.latitude = mapRegion.center.latitude;
    lastLocationCoordinate.longitude = mapRegion.center.longitude;

}

Hope that sends you in the right direction.

distanceFromLocation is iOS 3.2 and later. initWithLatitude is iOS 2.0 and later. MKCoordinateRegion is iOS 3.0 and later. MKMapView centerCoordinate is iOS 3.0 and later.

Also- please feel free to jump in and set me straight where I've erred. I'm figuring all of this out myself- but this is working fairly well for me so far.

Hope this helps someone.


First lesson: Don't ask questions late night on SO.

Second lesson: you can achieve this simply by construction a CGPoint from the user's current location, and a CGPoint from the MapView center.

With two points, just calculate the distance, and see if it's past a certain threshold.

You can also construct a CGRect around the map center, and check CGRectContainsPoint if that's easier.

- (BOOL) isUserPointInsideMapCenterRegion
{
    CLLocation * ul = _mapView.userLocation.location;

    CGPoint userPoint = [_mapView convertCoordinate: ul.coordinate toPointToView: _mapView];
    CGPoint mapPoint = [_mapView convertCoordinate: _mapView.centerCoordinate toPointToView: _mapView];

    if (fabs(userPoint.x - mapPoint.x) > MAP_CENTER_RECTANGLE_SIZE || fabs(userPoint.y - mapPoint.y) > MAP_CENTER_RECTANGLE_SIZE)
    {
        return NO;
    }

    return YES;
}


I realise this question is a bit old now, but I feel that the answer described in this other question is more robust because the delegate method could be fired for any reason. Using a UIPanGestureRecognizer to detect the scroll means that the user manually scrolled the map, and it can check if the map has scrolled X pixels, instead of relying on meters, which means the user has scrolled more or less depending on the zoom level.

https://stackoverflow.com/a/11675587/159758

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜