【发布时间】:2010-11-29 02:00:05
【问题描述】:
我的应用知道当前的用户位置(CoreLocation.framework)。 一旦用户打开一个新的 MapView,他的 iPhone 就会再次开始搜索当前位置。 是否可以跳过或更改 mkMapView 的第一个用户位置?
编辑:
是否可以覆盖 MKMapView 并使用其他 LocationManager?
【问题讨论】:
标签: iphone cocoa-touch mkmapview core-location
我的应用知道当前的用户位置(CoreLocation.framework)。 一旦用户打开一个新的 MapView,他的 iPhone 就会再次开始搜索当前位置。 是否可以跳过或更改 mkMapView 的第一个用户位置?
编辑:
是否可以覆盖 MKMapView 并使用其他 LocationManager?
【问题讨论】:
标签: iphone cocoa-touch mkmapview core-location
是的,可以有一个单独的位置管理器对象并将其值分配给地图视图(顺便说一句,我使用下面的 '=' 作为列表前缀,以防止 SO 代码格式化程序出现问题)。
= 在您的UIViewController 中维护两个独立的属性:一个到MKMapView,一个到CLLocationManager。
= 使用MKMapView 和您想要的任何其他窗口镶边创建一个 XIB 文件。将插座连接到控制器属性。确保 MKMapView 不关注用户位置。
= 让 UIViewController 实现CLLocationManagerDelegate 协议——尤其是locationManager:didUpdateToLocation:fromLocation: 方法,只要有新的位置值可用,就会调用该方法。我们将控制器设置为位置管理器的委托。
= 在 viewController 的 loadView 方法中,加载带有 MKMapView 的 NIB。为了给用户反馈,您可能需要设置一个UIActivityIndicatorView 微调器并将其设置为startAnimating。然后你开始:
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
self.locationManager.distanceFilter = 10; // or whatever
[self.locationManager startUpdatingLocation];
= 在locationManager:didUpdateToLocation:fromLocation: 中检查事件是否在最后 N 秒后更新。然后告诉位置管理器停止更新,让微调器停止动画,并获取纬度/经度数据并将其与视图跨度和区域一起分配给地图视图,以便它缩放并居中到正确的位置。
= 现在是棘手的部分:蓝色大理石“颤抖”是 mapview 跟踪用户位置的一个特征。您将不得不暂时“伪造”它,直到真正的人开始出现(或者只是为当前位置使用单独的标记并自己保持其位置)。我个人会选择用户熟悉的蓝色大理石。
= 要让它在启动时正确显示,您需要创建一个自定义 MKAnnotationView,只在位置管理器返回的位置添加蓝色大理石图形。这意味着拍摄 Mapview 的快照并显示位置,然后将蓝色大理石用 Photoshop 处理出来并将其用作自定义注释视图的图像。
= 如果您希望它主动跟随地图,您可以启用地图视图的用户位置跟踪,当它获取实际数据时,您隐藏之前设置的标记并让地图视图进行更新。另一种选择是允许现有的位置管理器继续每秒钟左右接收更新,并自己更新蓝色大理石注释的位置。
= 让 mapview 自己的 userLocation 更新添加到 viewDidLoad:
[self.map.userLocation addObserver:self
forKeyPath:@"location"
options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)
context:NULL];
self.map.showsUserLocation = YES; // starts updating user location
= 实施observeValueForKeyPath。当 mapview 的 userlocation 的 location 属性具有值时调用它:
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([self.map isUserLocationVisible]) {
[self.locationManager stopUpdatingLocation];
self.ownBlueMarble.hidden = YES;
}
// The current location is in self.map.userLocation.coordinate
}
= 为了避免显示当前位置时的预热延迟,请保留对包含地图和位置管理器的 viewController 的引用,这样它就不会消失(这有点占用内存,但如果你释放它,你'将不得不再次等待,直到 MapView 加载图块并准备就绪)。
= 在viewWillLoad 中,您可以将最后一个已知位置填充到自定义 bluemarble 注释中并显示它。打开/关闭 userLocation 跟踪,当您收到通知时,相同的 hide-the-annotation-show-the-real-marble 技巧将起作用。地图视图自己的位置管理器启动,当它有数据时,您可以让您的注释标记消失。
= 您可能希望实现 viewController 的 viewWillDisappear 方法并手动关闭地图视图上的 userLocation 跟踪,以便在下次打开视图时默认关闭。您还需要获取最后一个已知的userLocation 并将其保存以备下次使用。这样,您可以在 viewWillAppear 方法中完成所有定位标记杂耍,而不必担心 userLocation 会干扰,直到您准备好。
祝你好运。
【讨论】:
在您的控制器中:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CLLocationCoordinate2D coord = {latitude: 37.423617, longitude: -122.220154};
MKCoordinateSpan span = {latitudeDelta: 1, longitudeDelta: 1};
MKCoordinateRegion region = {coord, span};
[mapView setRegion:region];
}
当地图出现时,它将位于帕洛阿尔托附近
【讨论】:
尝试在初始化时将 showUserLocation 属性设置为 false,然后将 region 恢复为之前的地图视图(您显然必须在之前的地图被销毁之前存储它)。
这是你想要的吗?
【讨论】:
您无需使用其他位置管理器,您可以将任何您想要的点添加到地图并通过您想要的任何其他逻辑更新它们。
假设您有一个与遥控汽车的套接字连接,并且该汽车在有效负载中发回包含地理位置信息的套接字数据。您可以将其解析出来,并实时更新地图上缩略图的位置。不需要“userLocation”属性,但如果您愿意,可以显示它。
用户的位置是只读的,可以使用也可以不使用。这并不意味着您需要另一个位置经理来做您可能需要做的任何事情。听起来您的应用并不真正需要该功能,但我可能误解了您的问题。
【讨论】: