相对于缩放级别缩放 MKMapView 注释
问题 我正在尝试围绕注释创建一个视觉半径圆,该圆实际上保持固定大小。例如。因此,如果我将半径设置为 100m,当您缩小地图视图时,半径圆会逐渐变小。
我已经能够实现缩放,但是当用户操纵视图时,半径矩形/圆似乎会“抖动”远离图钉地标。
我相信这在即将推出的 iPhone OS 4 上更容易实现,但我的应用程序需要支持 3.0。
表现 这是该行为的视频。
实施 注释以通常的方式添加到 Mapview 中,并且我在 UIViewController 子类 (MapViewController) 上使用了委托方法来查看区域何时发生变化。
-(void)mapView:(MKMapView *)pMapView regionDidChangeAnimated:(BOOL)animated{
//Get the map view
MKCoordinateRegion region;
CGRect rect;
//Scale the annotations
for( id<MKAnnotation> annotation in [[self mapView] annotations] ){
if( [annotation isKindOfClass: [Location class]] && [annotation conformsToProtocol:@protocol(MKAnnotation)] ){
//Approximately 200 m radius
region.span.latitudeDelta = 0.002f;
region.span.longitudeDelta = 0.002f;
region.center = [annotation coordinate];
rect = [[self mapView] convertRegion:region toRectToView: self.mapView];
if( [[[self mapView] viewForAnnotation: annotation] respondsToSelector:@selector(setRadiusFrame:)] ){
[[[self mapView] viewForAnnotation: annotation] setRadiusFrame:rect];
}
}
}
Annotation 对象 (LocationAnnotationView) 是 MKAnnotationView 的子类,它的 setRadiusFrame 看起来像这样
-(void) setRadiusFrame:(CGRect) rect{
CGPoint centerPoint;
//Invert
centerPoint.x = (rect.size.width/2) * -1;
centerPoint.y = 0 + 55 + ((rect.size.height/2) * -1);
rect.origin = centerPoint;
[self.radiusView setFrame:rect];
}
最后,radiusView 对象是 UIView 的子类,它重写了 drawRect 方法来绘制半透明圆圈。 setFrame 在此 UIView 子类中也被重写,但除了 [UIView setFrame:] 之外,它仅用于调用 [UIView setNeedsDisplay] 以确保在更新框架后重新绘制视图。
radiusView 对象的(CircleView)drawRect 方法如下所示
-(void) drawRect:(CGRect)rect{
//NSLog(@"[CircleView drawRect]");
[self setBackgroundColor:[UIColor clearColor]];
//Declarations
CGContextRef context;
CGMutablePathRef path;
//Assignments
context = UIGraphicsGetCurrentContext();
path = CGPathCreateMutable();
//Alter the rect so the circle isn't cliped
//Calculate the biggest size circle
if( rect.size.height > rect.size.width ){
rect.size.height = rect.size.width;
}
else if( rect.size.height < rect.size.width ){
rect.size.width = rect.size.height;
}
rect.size.height -= 4;
rect.size.width -= 4;
rect.origin.x += 2;
rect.origin.y += 2;
//Create paths
CGPathAddEllipseInRect(path, NULL, rect );
//Create colors
[[self areaColor] setFill];
CGContextAddPath( context, path);
CGContextFillPath( context );
[[self borderColor] setStroke];
CGContextSetLineWidth( context, 2.0f );
CGContextSetLineCap(context, kCGLineCapSquare);
CGContextAddPath(context, path );
CGContextStrokePath( context );
CGPathRelease( path );
//CGContextRestoreGState( context );
}
感谢您的耐心配合,我们将不胜感激。 乔纳森
The Problem
I'm trying to create a visual radius circle around a annonation, that remains at a fixed size in real terms. Eg. So If i set the radius to 100m, as you zoom out of the Map view the radius circle gets progressively smaller.
I've been able to achieve the scaling, however the radius rect/circle seems to "Jitter" away from the Pin Placemark as the user manipulates the view.
I'm lead to believe this is much easier to achieve on the forthcoming iPhone OS 4, however my application needs to support 3.0.
The Manifestation
Here is a video of the behaviour.
The Implementation
The annotations are added to the Mapview in the usual fashion, and i've used the delegate method on my UIViewController Subclass (MapViewController) to see when the region changes.
-(void)mapView:(MKMapView *)pMapView regionDidChangeAnimated:(BOOL)animated{
//Get the map view
MKCoordinateRegion region;
CGRect rect;
//Scale the annotations
for( id<MKAnnotation> annotation in [[self mapView] annotations] ){
if( [annotation isKindOfClass: [Location class]] && [annotation conformsToProtocol:@protocol(MKAnnotation)] ){
//Approximately 200 m radius
region.span.latitudeDelta = 0.002f;
region.span.longitudeDelta = 0.002f;
region.center = [annotation coordinate];
rect = [[self mapView] convertRegion:region toRectToView: self.mapView];
if( [[[self mapView] viewForAnnotation: annotation] respondsToSelector:@selector(setRadiusFrame:)] ){
[[[self mapView] viewForAnnotation: annotation] setRadiusFrame:rect];
}
}
}
The Annotation object (LocationAnnotationView)is a subclass of the MKAnnotationView and it's setRadiusFrame looks like this
-(void) setRadiusFrame:(CGRect) rect{
CGPoint centerPoint;
//Invert
centerPoint.x = (rect.size.width/2) * -1;
centerPoint.y = 0 + 55 + ((rect.size.height/2) * -1);
rect.origin = centerPoint;
[self.radiusView setFrame:rect];
}
And finally the radiusView object is a subclass of a UIView, that overrides the drawRect method to draw the translucent circles. setFrame is also over ridden in this UIView subclass, but it only serves to call [UIView setNeedsDisplay] in addition to [UIView setFrame:] to ensure that the view is redrawn after the frame has been updated.
The radiusView object's (CircleView) drawRect method looks like this
-(void) drawRect:(CGRect)rect{
//NSLog(@"[CircleView drawRect]");
[self setBackgroundColor:[UIColor clearColor]];
//Declarations
CGContextRef context;
CGMutablePathRef path;
//Assignments
context = UIGraphicsGetCurrentContext();
path = CGPathCreateMutable();
//Alter the rect so the circle isn't cliped
//Calculate the biggest size circle
if( rect.size.height > rect.size.width ){
rect.size.height = rect.size.width;
}
else if( rect.size.height < rect.size.width ){
rect.size.width = rect.size.height;
}
rect.size.height -= 4;
rect.size.width -= 4;
rect.origin.x += 2;
rect.origin.y += 2;
//Create paths
CGPathAddEllipseInRect(path, NULL, rect );
//Create colors
[[self areaColor] setFill];
CGContextAddPath( context, path);
CGContextFillPath( context );
[[self borderColor] setStroke];
CGContextSetLineWidth( context, 2.0f );
CGContextSetLineCap(context, kCGLineCapSquare);
CGContextAddPath(context, path );
CGContextStrokePath( context );
CGPathRelease( path );
//CGContextRestoreGState( context );
}
Thanks for bearing with me, any help is appreciated.
Jonathan
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,第一个函数中的
foo
使用了什么?我假设 RadiusView 的父级是注释视图,对吗?“抖动”
另外,radiusView 的中心点应该与annotationView 的中心点重合。这应该可以解决您的问题:
不必要的方法
您可以直接在
radiusView
上设置框架并避免上述计算:rect
drawRect:
,它不必与框架相同。直接使用 self.frame 更安全不必要的视图
现在,如果您需要使用上面的层次结构,我给出了以上几点,但我不明白为什么不直接在
LocationAnnotationView
?毕竟它就是为了这个目的而存在的。这样做的方法如下:缩放时,直接更改annotationView的矩形:
将
drawRect:
的实现移动到LocationAnnotationView
。这更容易实现,并且应该可以解决您的问题,因为注释视图的中心点随您的图钉移动,您不应该看到这个问题。
修复
代码中还有另外两个问题:
像这样设置 longitudeDelta:
转换为米的经度增量随纬度变化。或者,您可以只设置纬度增量,然后修改矩形,使其变为矩形 (
width==height
)。在
drawRect:
中,不要使用传递的rect
;而是使用 self.frame。不能保证它们是相同的,并且rect
可以有任何值。让我知道这些是否有效;-)
First, what's
foo
used in the first function? And I'm assumingradiusView
's parent is the annotation view, right?The "Jittering"
Also, the center point of
radiusView
should coincide with that of the annotationView. This should solve your problem:Unnecessary method
You could set the frame directly on the
radiusView
and avoid the above calculation:rect
passed todrawRect:
, it doesn't have to be the same as the frame. It's safer to directly useself.frame
Unnecessary view
Now I gave the above points if you need to use the above hierarchy, but I don't see why don't you just draw your ellipses directly in the
LocationAnnotationView
? It's there for this purpose after all. This is how you do this:when scaling, change the annotationView's rect directly:
Move the implementation of
drawRect:
toLocationAnnotationView
.This is easier to implement, and should address your problem as the center point of the annotation view moves with your pin and you shouldn't see this problem.
Fixes
There are two other issues in the code:
Set longitudeDelta like this:
as the longitude delta converted to meters changes with the latitude. Alternatively, you could only set latitude delta, then modify the rect so it becomes rectangular (
width==height
).in
drawRect:
, don't use the passedrect
; instead useself.frame
. There's no guarantee that these are the same, andrect
could have any value.Let me know if these work ;-)