我想在 MKMapView 上做叠加。所以我创建了我的自定义对象:
@interface Spot : NSObject
@property int spot_id;
@property CLLocationCoordinate2D coordinate;
@property float radius;
@property NSObject<MKOverlay> * overlay;
- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(float)radius;
@end
有一个后端,不断更新 Spots 并将它们传送到手机。所以我必须:
- 检查当前渲染的点是否仍然有效
- 如果是,他们是否移动或改变了半径?如果是这样,请更新它们(移动?/删除+重绘?!)
- 如果它们不再存在则删除。
是否有更好的方法来跟踪叠加层?保持 NSObject<MKoverlay> *
每个位置都附有引用并不断重新分配,这让我觉得有点奇怪。
最佳答案
这里好像有3个问题:
如何检测服务器中 Blob 的变化?
执行此操作的丑陋方法是遍历您的位置并查看
coordinate
是否和/或radius
变了。更好的办法是让服务器更新创建、修改和删除时间戳或其他一些标识符,这样客户端就可以检索自上次更新以来的所有创建、修改和/或删除。最好是将其与某种形式的推送通知结合起来,这样客户也会主动收到这些更改的通知。这个问题很难抽象地回答。这在很大程度上取决于您的服务器的功能和数据库的性质(例如,有多少“点”,它们更改的频率等)。这既会影响客户端-服务器架构,也会影响客户端实现。
如何在地点变化时更新 map ?
这是一个简单得多的问题。插入和删除很容易。你只要做
addOverlay:
(或者,在 iOS 7 中,addOverlay:level:
和removeOverlay:
。对于更新,虽然它不够优雅,但我认为最简单的方法是删除旧的叠加层并将其重新添加,viewForOverlay
将负责用户界面为你。Spot
的正确结构是什么?类(class)?就像一个想法,但拥有您的
coordinate
似乎是重复的和radius
属性,然后有一个id<MKOverlay> overlay
对象(因为这可能是一个具有相同两个属性的MKCircle
)。如果您的叠加层将是MKCircle
对象,可能更容易有一个Spot
类本身,以符合MKOverlay
:@interface Spot : NSObject <MKOverlay> @property (nonatomic) int spot_id; @property (nonatomic) CLLocationCoordinate2D coordinate; @property (nonatomic) CLLocationDistance radius; @property (nonatomic, readonly) MKMapRect boundingMapRect; - (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius; @end
然后,您需要做的就是执行
boundingMapRect
和intersectsMapRect
:- (MKMapRect) boundingMapRect { MKMapPoint point = MKMapPointForCoordinate(self.coordinate); CLLocationDistance distance = self.radius * MKMetersPerMapPointAtLatitude(self.coordinate.latitude); MKMapRect rect = MKMapRectMake(point.x, point.y, distance * 2.0, distance * 2.0); rect = MKMapRectOffset(rect, -distance, -distance); return rect; } - (BOOL)intersectsMapRect:(MKMapRect)mapRect { return MKMapRectIntersectsRect(mapRect, [self boundingMapRect]); }
您可能需要仔细检查
boundingMapRect
逻辑,但我认为这是正确的。然后你可以添加和删除
Spot
对象作为覆盖本身。你需要做的就是实现一个viewForOverlay
在你的MKMapViewDelegate
,例如,在 iOS 7 之前的版本中,这将是:- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay { if ([overlay isKindOfClass:[Spot class]]) { Spot *spot = (id)overlay; MKCircle *circle = [MKCircle circleWithCenterCoordinate:spot.coordinate radius:spot.radius]; MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:circle]; overlayView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2]; overlayView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; overlayView.lineWidth = 3.0; return overlayView; } return nil; }
在 iOS 7 中,这将是:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay { if ([overlay isKindOfClass:[Spot class]]) { Spot *spot = (id)overlay; MKCircle *circle = [MKCircle circleWithCenterCoordinate:spot.coordinate radius:spot.radius]; MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:circle]; renderer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2]; renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; renderer.lineWidth = 3; return renderer; } return nil; }
另一种方法是定义您的
Spot
作为:@interface Spot : NSObject <MKOverlay> @property (nonatomic) int spot_id; @property (nonatomic, strong) MKCircle *overlay; - (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
然后你可以定义
boundingMapRect
和coordinate
从MKCircle
返回适当的值(使您不必自己编写):- (MKMapRect)boundingMapRect { return [self.circle boundingMapRect]; } - (CLLocationCoordinate2D)coordinate { return [self.circle coordinate]; }
显然
init
方法会改变:- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius; { self = [super init]; if (self) { _spot_id = spot_id; _circle = [MKCircle circleWithCenterCoordinate:coordinate radius:radius]; } return self; }
与
viewForOverlay
一样(7.0 之前的 iOS 版本)在MKMapViewDelegate
:- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay { if ([overlay isKindOfClass:[SpotCircle class]]) { SpotCircle *spot = (id)overlay; MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:spot.circle]; overlayView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2]; overlayView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; overlayView.lineWidth = 3.0; return overlayView; } return nil; }
在 iOS 7 中,这将是:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay { if ([overlay isKindOfClass:[SpotCircle class]]) { SpotCircle *spot = (id)overlay; MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:spot.circle]; renderer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2]; renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7]; renderer.lineWidth = 3; return renderer; } return nil; }
希望对您有所帮助。
关于ios - 在 MKMapView 上更新和组织覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16501587/