【问题标题】:Rotate annotation image on MKMapView在 MKMapView 上旋转注释图像
【发布时间】:2014-07-27 00:36:10
【问题描述】:

我正在尝试旋转作为注释添加到 MKMapView 的图像。

这是代码:

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:   (id<MKAnnotation>)annotation
{
  if (! [annotation isKindOfClass:[IGAMapAnnotation class]])
  {
    //return default view if annotation is NOT of type IGAMapAnnotation...
    return nil;
  }


  MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:@"IGAMapAnnotation"];

  if (annotationView == nil)
  {
    annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"IGAMapAnnotation"];

    annotationView.enabled = YES;
    annotationView.canShowCallout = YES;
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
  }
  else
  {
    annotationView.annotation = annotation;
  }

  IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;

  // THIS IS IT!
  if ([myLocation.type isEqual: @"PLANE"]) {
    UIImage *planeImage = [UIImage imageNamed:@"planetracked.png"];

    UIImageView *planeImageView = [[UIImageView alloc]initWithImage:planeImage];
    planeImageView.transform = CGAffineTransformMakeRotation(M_PI_2);

    annotationView.image = planeImageView;
  }

  return annotationView;
}

这显然给了我一个错误,因为 annotationView.image 应该分配一个图像而不是 UIImageView。我尝试了各种方法只旋转图像,例如:

- (UIImage *)rotateImage:(UIImage *)image onDegrees:(NSString *)heading {

  double angle = [heading doubleValue];

  CGSize s = {image.size.width, image.size.height};
  UIGraphicsBeginImageContext(s);
  CGContextRef ctx = UIGraphicsGetCurrentContext();
  CGContextTranslateCTM(ctx, 0,image.size.height);
  CGContextScaleCTM(ctx, 1.0, -1.0);

  CGContextRotateCTM(ctx, 2*M_PI*angle/360);
  CGContextDrawImage(ctx,CGRectMake(0,0,image.size.width, image.size.height),image.CGImage);
  UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return newImage;
}

它们也不起作用——地图上没有图像。

有人知道如何在 MKMapView 上旋转注释图像吗?

万分感谢!

【问题讨论】:

  • 而不是annotationView.image = planeImageView;,这绝对是错误的,试试[annotationView addSubview:planeImageView];。另请注意,如果type 不是“PLANE”,则注释将不可见,因为不会设置任何图像,因此您应该添加else 部分以防万一。
  • 安娜。太感谢了。它成功了。图像被旋转。现在的问题是在更新注释时将其从地图中删除(在我的情况下,它们每 5 秒更新一次)。我正在使用这个:[self.mapView removeAnnotations:mapLocations]; 但图像没有被删除。此外,我注意到它可能出现在地图上的不同地方,尽管坐标没有改变。我想知道为什么。非常感谢!

标签: ios uiimageview uiimage mkmapview mkannotationview


【解决方案1】:

代替:

annotationView.image = planeImageView;

这绝对是错误的(image 属性是 UIImageplaneImageViewUIImageView),使用addSubview:UIImageView 添加到注释视图(保留视图的image属性nil 且未使用)。

但是,您还需要进行一些其他调整,以便:

  • 图像以坐标为中心(而不是其角),并且
  • 点击图像上的任意位置会显示标注(而不是仅一个特定角)

要执行这些操作,请增加两个视图的帧大小以考虑旋转可能产生的最大宽度(假设图像是正方形,这是原始宽度的 2 倍的平方根)并设置图像视图的 @987654330 @ 到“中心”,因此图像不会因这些帧大小变化而失真。

另一个大问题是,如果您的IGAMapAnnotations 的type 不是“PLANE”,那么它们将是:

  • 如果创建了 new 注释视图,则不可见(因为未设置 image 也未将任何子视图添加到注释视图中),或者,
  • 显示带有某些其他注释标题的“平面”图像,因为注释视图已出列(并且正在重新用于另一个注释)。

为了避免两种类型的注解(“plane”/“not plane”)重用彼此的视图,我建议为每个type不是每个注释)并将特定于类型的更改应用于视图。

修改后的viewForAnnotation 方法如下所示:

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    if (! [annotation isKindOfClass:[IGAMapAnnotation class]])
    {
        //return default view if annotation is NOT of type IGAMapAnnotation...
        return nil;
    }

    IGAMapAnnotation *myLocation = (IGAMapAnnotation *)annotation;

    BOOL typeIsPlane = [myLocation.type isEqualToString:@"PLANE"];
    int planeImageViewTag = 42;

    NSString *reuseId = typeIsPlane ? @"IGAMapAnnotationPlane" : @"IGAMapAnnotationOther";

    MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];

    if (annotationView == nil)
    {
        annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
        annotationView.enabled = YES;
        annotationView.canShowCallout = YES;
        annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

        if (typeIsPlane)
        {
            //Here, just add the image view to the annotation view with no
            //rotation.  Only want to add the image view to the annotation
            //view ONCE when the annotation view is initially created.  If
            //view is dequeued, it will already have an image view and we
            //just update its rotation.

            UIImage *planeImage = [UIImage imageNamed:@"planetracked.png"];

            UIImageView *planeImageView = [[UIImageView alloc] initWithImage:planeImage];
            planeImageView.tag = planeImageViewTag;
            planeImageView.contentMode = UIViewContentModeCenter;

            [annotationView addSubview: planeImageView];

            CGRect avFrame = annotationView.frame;
            //"1.5" on next line is the square root of 2 rounded up a bit.
            avFrame.size = CGSizeMake(planeImage.size.width*1.5, 
                                      planeImage.size.height*1.5);
            annotationView.frame = avFrame;
            planeImageView.frame = annotationView.frame;
        }
        else
        {
            //If this IGAMapAnnotation is not a "plane",
            //show some other default image.
            //(Or, you could return nil to show a default red pin.)

            annotationView.image = [UIImage imageNamed:@"NotAPlane.png"];

            //May or may not need to set centerOffset.
            //Either remove or adjust 0,0 as needed to 
            //center the image on the coordinates.
            annotationView.centerOffset = CGPointMake(0, 0);
        }
    }
    else
    {
        annotationView.annotation = annotation;
    }

    //At this point, we have a new or dequeued annotation view ready
    //and pointing to the current annotation.
    //Now make any annotation-specific changes to the view...

    if (typeIsPlane)
    {
        UIImageView *planeImageView = (UIImageView *)[annotationView viewWithTag:planeImageViewTag];
        planeImageView.transform = CGAffineTransformMakeRotation(M_PI_2);
        //Replace M_PI_2 with rotation specific to this annotation's heading.
    }

    return annotationView;
}

顺便说一句,使用isEqualToString: 而不是isEqual:NSStrings。


对于removeAnnotations: 问题,必须是mapLocations 包含地图上注释的 实例。要删除现有注释,您必须提供对最初添加的完全相同对象的引用。

如果您总是删除 all 注释并重新添加 all 注释,则可以使用 [self.mapView removeAnnotations:self.mapView.annotations];

如果您只是删除 一些 注释,则需要保留对最初添加的注释的引用或遍历地图视图的 annotations 数组并确定应该删除哪些注释(保留临时 NSMutableArray 作为“要删除的注释”列表),然后使用要删除的注释列表调用 removeAnnotations:

【讨论】:

  • 安娜。再次感谢你!这很棒。因此,我添加了几种类似于 typeIsPlane 的图像类型。我还在 ViewWillAppear 以及每 5 秒获取平面坐标并在地图上绘制其图像的方法中添加了以下代码:[self.mapView removeAnnotations:self.mapView.annotations];mapLocations = [[NSMutableArray alloc]init];[self addAnnotation]; 现在,我的最后一个问题是其他类型的图像(飞机除外)每次更新地图时都会继续旋转,因此不时放置错误的图像。神秘! :-) 非常感谢!
  • 如何确保注释相对于地图旋转本身正确旋转。因此,如果用户手动旋转地图视图,您如何考虑这一点。我可能会就此发布一个问题,因为我还没有找到解决方案 - 但希望是简单的。
【解决方案2】:

以下似乎有效。万分感谢 Anna,没有她就没有她!

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

  if (! [annotation isKindOfClass:[IGAMapAnnotation class]]) {
    return nil;
  }

  IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;

BOOL typeIsPlane = [myLocation.navaidType isEqualToString:@"PLANE"];
BOOL typeIsOne  = [myLocation.navaidType isEqualToString:@"ONE"];
BOOL typeIsTwo = [myLocation.navaidType isEqualToString:@"TWO"];
BOOL typeIsThree = [myLocation.navaidType isEqualToString:@"THREE"];

int planeImageViewTag = 42;

NSString *reuseId;
if (typeIsPlane)
    reuseId = @"IGAMapAnnotationPlane";

else if (typeIsOne)
    reuseId = @"IGAMapAnnotationOne";

else if (typeIsTwo)
    reuseId = @"IGAMapAnnotationTwo";

else if (typeIsThree)
    reuseId = @"IGAMapAnnotationThree";

else
    reuseId = @"IGAMapAnnotationOther";

MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];

if (annotationView == nil)
{
    annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
    annotationView.enabled = YES;
    annotationView.canShowCallout = YES;
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

    if (typeIsPlane)
    {

        UIImage *planeImage = [UIImage imageNamed:@"mapPLANE.png"];

        UIImageView *planeImageView = [[UIImageView alloc] initWithImage:planeImage];
        planeImageView.tag = planeImageViewTag;
        planeImageView.contentMode = UIViewContentModeCenter;

        [annotationView addSubview: planeImageView];

        CGRect avFrame = annotationView.frame;
        //"1.5" on next line is the square root of 2 rounded up a bit.
        avFrame.size = CGSizeMake(planeImage.size.width*1.5,
                                  planeImage.size.height*1.5);
        annotationView.frame = avFrame;
        planeImageView.frame = annotationView.frame;
    }

    else if (typeIsOne)
    {
        annotationView.image = [UIImage imageNamed:@"one.png"];
        annotationView.centerOffset = CGPointMake(0, 0);
    }

    else if (typeIsTwo)
    {
        annotationView.image = [UIImage imageNamed:@"two.png"];
        annotationView.centerOffset = CGPointMake(0, 0);
    }

    else if (typeIsThree)
    {
        annotationView.image = [UIImage imageNamed:@"three.png"];
        annotationView.centerOffset = CGPointMake(0, 0);
    }

    else
        return nil;
}

else
{
    annotationView.annotation = annotation;
}

if (typeIsPlane)
{
    // Convert current heading string to double
    double headingDouble = [currentHeading doubleValue];

    UIImageView *planeImageView = (UIImageView *)[annotationView viewWithTag:planeImageViewTag];
    planeImageView.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(headingDouble));
}

return annotationView;

}

【讨论】:

  • 您能说明如何应用 currentHeading 的值吗?
猜你喜欢
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多