如何在使用MKMapView时设置准确度和距离过滤器

29

当我使用MKMapViewsetShowsUserLocation来跟踪用户位置时,如何设置精度和距离筛选器?我指的不是CLLocationManager

谢谢。

3个回答

84

你无法控制内部MKMapView位置管理器(用于跟踪带有蓝点的用户)的准确性,但你可以创建自己的位置管理器并使用它来重新定位地图。以下是一个操作步骤...

处理核心位置权限

在Core Location Delegate中:

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied){
        NSLog(@"User has denied location services");
    } else {
        NSLog(@"Location manager did fail with error: %@", error.localizedFailureReason);
    }
}

在设置位置管理器之前:

if (![CLLocationManager locationServicesEnabled]){
    NSLog(@"location services are disabled"];
    return;
}
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied){
    NSLog(@"location services are blocked by the user");
    return;
}
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized){
    NSLog(@"location services are enabled");
}  
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined){
    NSLog(@"about to show a dialog requesting permission");
}

设置核心位置

self.locationManager = [CLLocationManager new];
self.locationManager.purpose = @"Tracking your movements on the map.";
self.locationManager.delegate = self;

/* Pinpoint our location with the following accuracy:
 *
 *     kCLLocationAccuracyBestForNavigation  highest + sensor data
 *     kCLLocationAccuracyBest               highest     
 *     kCLLocationAccuracyNearestTenMeters   10 meters   
 *     kCLLocationAccuracyHundredMeters      100 meters
 *     kCLLocationAccuracyKilometer          1000 meters 
 *     kCLLocationAccuracyThreeKilometers    3000 meters
 */
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;

/* Notify changes when device has moved x meters.
 * Default value is kCLDistanceFilterNone: all movements are reported.
 */
self.locationManager.distanceFilter = 10.0f;

/* Notify heading changes when heading is > 5.
 * Default value is kCLHeadingFilterNone: all movements are reported.
 */
self.locationManager.headingFilter = 5;

// update location
if ([CLLocationManager locationServicesEnabled]){
    [self.locationManager startUpdatingLocation];
}

使用我们的位置管理器重新居中地图

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation 
{
    MKCoordinateRegion region = { { 0.0f, 0.0f }, { 0.0f, 0.0f } };
    region.center = newLocation.coordinate;
    region.span.longitudeDelta = 0.15f; 
    region.span.latitudeDelta = 0.15f;
    [self.mapView setRegion:region animated:YES];
}

将其委托给代理。MKMapView没有距离或准确性过滤器,只有CLLocationManager拥有这个功能。MKMapView有的是以一个点为中心的区域范围,在上面的示例中为0.15度(0.15 * 111公里)。

我尝试了但没成功的方法

文档没有说明MKMapView从哪里获取更新。 我尝试了以下方法:

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation {
    NSLog(@"newLocation %@", newLocation.timestamp);
    NSLog(@"last map location %@", [NSString stringWithFormat:@"%@",[[[self.mapView userLocation] location] timestamp]]);
}

我在每个地方得到不同的值。看起来 MKMapView 使用它自己的 CLLocationManager,这意味着你不能设置其准确度。你也不能为 MKMapViewCLLocationManager 添加委托。

我的印象是唯一的方法是将显示用户位置设置为 NO,并创建一个带有蓝点标注的自定义标注,这意味着需要手动重新定位地图,如发布的内容所述。你可以从 SDK 中获取蓝色点图形,使用 github 项目 artwork-extractor。

我不知道是否遗漏了什么或者这部分 MKMapView 只是糟糕。


1
您提供的代码是用于CLLocationManager而不是MKMapView。 - Van Du Tran
嗨Jano,如果我也使用[MKMapView setShowsUserLocation],那么我不会同时运行两个位置请求进程吗?一个来自MKMapView,另一个来自CLLocation Manager?再次感谢您的澄清。 - Van Du Tran
我猜你会这么做。如果你想要自定义准确性,我建议使用自定义注释并将其设置为NO。看起来像是一个解决方法,但我不知道是否有更好的方法。我会点赞这个问题,并希望得到其他人的意见。 - Jano
@VanDuTran 避免使用手动发布的自定义注释。如果设备移动速度较快,它会消耗CPU速度。更好的方法是添加UIImageView包装在“蓝点”周围,作为MKMapView视图的子视图 - 这将使用GPU来渲染注释,只要不可能滚动地图就可以工作。 - Pétur Ingi Egilsson

3

以下是一个显示地图的示例代码。

首先在您的.h文件中导入MKMapKit和CoreLocation框架。

#import <MapKit/MapKit.h>
 #import <CoreLocation/CoreLocation.h>

在.h文件中添加MKMapKit和CoreLocation代理
@interface MapViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate>


CGPoint gameMapCenter = CGPointMake([[UIScreen mainScreen] bounds].size.width / 2, [[UIScreen mainScreen] bounds].size.height / 2);
    gameMapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 640, 620)];
    [gameMapView setCenter:gameMapCenter];
    [gameMapView setMapType:MKMapTypeStandard];
    [gameMapView setDelegate:self];
    [self.view addSubview:gameMapView];
    [gameMapView setShowsUserLocation:YES];

使用CLLocationManager获取用户位置。

声明一个CLLocationManager实例。

CLLocationManager *locationManager;

ViewDidLoad
locationManager = [[CLLocationManager alloc] init];

[locationManager setDelegate:self];

[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];

[locationManager setDistanceFilter:kCLDistanceFilterNone];

[locationManger startUpdatingLocation];

startUpdatingLocation方法实现:

(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 
{
      //Your Stuff
}

是的,但我需要显示地图...地图是我的应用程序的主视图。 - Van Du Tran
@VanDuTran 你好,我在这里更新了我的答案,你可以找到如何添加地图视图以及获取用户位置的方法。 - Gajendra Rawat
因为这个 [gameMapView setShowsUserLocation:YES]; 和 [locationManger startUpdatingLocation];,你会收到两次通知吗? - Van Du Tran
@VanDuTran 不会的,map拥有的CLLocationManager与你所拥有的CLLocationManager是分开的。 - Andrea Gottardo

2

您无法设置准确度,但是您可以通过 MKMapView 委托方法中的 userLocation 获取准确度。

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    NSLog(@"%f", userLocation.location.horizontalAccuracy);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接