相对于缩放级别缩放 MKMapView 注释

Posted

技术标签:

【中文标题】相对于缩放级别缩放 MKMapView 注释【英文标题】:Scaling MKMapView Annotations relative to the zoom level 【发布时间】:2011-02-22 17:12:03 【问题描述】:

问题 我正在尝试围绕 annonation 创建一个视觉半径圆,该圆实际上保持固定大小。例如。因此,如果我将半径设置为 100m,当您缩小地图视图时,半径圆会逐渐变小。

我已经能够实现缩放,但是当用户操纵视图时,半径矩形/圆似乎“抖动”远离 Pin Placemark。

我相信这在即将推出的 iPhone OS 4 上更容易实现,但是我的应用程序需要支持 3.0。

显化 这是video 的行为。

实施 注释以通常的方式添加到 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 );


感谢您对我的支持,感谢您提供任何帮助。 乔纳森

【问题讨论】:

【参考方案1】:

首先,第一个函数中使用的foo 是什么?而且我假设radiusView 的父级是注释视图,对吧?

“抖动”

另外,radiusView 的中心点应该与 annotationView 的中心点重合。这应该可以解决您的问题:

-(void) setRadiusFrame:(CGRect)rect
    rect.origin.x -= 0.5*(self.frame.size.width - rect.size.width);
    rect.origin.y -= 0.5*(self.frame.size.height - rect.size.height);
    [self.radiusView setFrame:rect]

不必要的方法

你可以直接在radiusView上设置框架,避免上面的计算:

    UIView * radiusView = [[[self mapView] viewForAnnotation: annotation] radiusView];
    rect = [[self mapView] convertRegion:foo toRectToView: radiusView.superView];
    [radiusView setFrame:rect];
    绘制椭圆时,不要使用传递给drawRect:rect,它不必与边框相同。直接使用self.frame更安全

不必要的视图

现在如果你需要使用上面的层次结构,我给出了以上几点,但我不明白你为什么不直接在LocationAnnotationView中画你的椭圆?毕竟是为了这个目的。这就是你这样做的方式:

    缩放时,直接改变annotationView的rect:

    rect = [[self mapView] convertRegion:foo toRectToView: self.mapView];
    [[[self mapView] viewForAnnotation: annotation] setFrame:rect];
    

    drawRect:的实现移动到LocationAnnotationView

这更容易实现,并且应该可以解决您的问题,因为注释视图的中心点会随着您的图钉移动,您应该不会看到这个问题。

修复

代码中还有两个问题:

    像这样设置 longitudeDelta:

    region.span.longitudeDelta = 0.002*cos(region.center.latitude*pi/180.0);
    

    因为转换为米的经度增量随纬度而变化。或者,您可以只设置纬度增量,然后修改矩形,使其变为矩形 (width==height)。

    drawRect:中,不要使用传递的rect;而是使用self.frame。不能保证它们是相同的,rect 可以有任何价值。

让我知道这些是否有效;-)

【讨论】:

问。首先,第一个函数中使用的 foo 是什么? A. 编码错误,我在那里留下了一个名为 foo 的变量进行测试, foo 应该是 (MKRegion)region :) Q. 我假设 radiusView 的父级是注释视图,对吗? A. 就视图层次结构而言,是的。 Q. 不必要的视图 A. 日食是根据接近度着色的,所以我想分开代码。我也希望能够以通用的方式重用它们。所以使用 UIView 比使用 MKAnnotationView 更方便。我会试试你的修复方法,非常感谢您花时间回答! 我显然不知道你的确切型号,但我仍然认为你的不同颜色的问题仍然可以通过一个视图来解决。毕竟annotation、annotation view、radiusView之间是一一对应的关系;任何一个视图都可以从注释或其他东西中获取颜色,因此模块化应该不难实现。无论如何,我只是大声思考,没关系;-)

以上是关于相对于缩放级别缩放 MKMapView 注释的主要内容,如果未能解决你的问题,请参考以下文章

MKMapView 缩放以显示框架中的所有注释

如果在添加注释时缩放,MKMapView 会崩溃

考虑缩放级别的两点之间的 CLLocationCoordinate2D 距离

MKMapView 缩放和区域

将 MKMapView 缩放到 MKAnnotationView 的框架

在 MKMapView 上绘制网格