Resize MKAnnotationView Image 当地图放大和缩小时?

Posted

技术标签:

【中文标题】Resize MKAnnotationView Image 当地图放大和缩小时?【英文标题】:Resize MKAnnotationView Image When map zooms in and out? 【发布时间】:2011-11-27 15:42:14 【问题描述】:

我有什么

我在地图上有大约 150 个 MKAnnotationViews。 每个 MKAnnotationView 都有一个替换默认 pin 的图像。

现在发生了什么

当地图放大时,MKAnnotationViews 会变小,而缩小时则相反。

我希望发生的事情

嗯,我希望它是相反的方式。因为当地图很小时,我希望 MKAnnotationViews 会更小,以便用户可以看到所有这些,而当他放大时,我希望它们会更大。

到目前为止我有什么代码

我知道如何获得缩放变化,并且我知道我可以获得“pMapView.region.span.latitudeDelta”作为缩放量的参考。我知道我可以更改 annotationView.frame。

-(void)mapView:(MKMapView *)pMapView regionDidChangeAnimated:(BOOL)animated
    NSLog(@"mapView.region.span.latitudeDelta = %f",pMapView.region.span.latitudeDelta);
    for (id <MKAnnotation> annotation in pMapView.annotations) 
        MKAnnotationView *annotationView  = [pMapView viewForAnnotation: annotation];
    

有人可以帮我吗? 谢谢 山尼

【问题讨论】:

【参考方案1】:

实际上在默认的 MKMapView 上 - 注释(例如图钉或图像)和标注(例如气泡)在您放大或缩小时保持相同的大小。它们不缩放。但我明白你的意思——就地图而言,它们似乎随着地图的缩小而增长,而随着地图的放大而缩小。

因此,您的问题有两种解决方案,它们的工作方式略有不同:

    实施 MKMapViewDelegate 协议参考中的 -(void)mapView:(MKMapView *)pMapView regionDidChangeAnimated:(BOOL)animated - 您已经完成了。 将UIPinchGestureRecognizer 附加到 MKMapView 对象,然后执行操作。

选项 #1 - mapView:regionDidChangeAnimated: 将在滚动或缩放事件中调用 - 基本上是在地图区域发生变化的任何时候,顾名思义。这会导致图标大小调整的平滑度稍微降低,因为地图事件的触发频率较低。

我的偏好是选项#2 - 将UIPinchGestureRecognizer 附加到 MKMapView 对象,然后执行操作。捏手势事件触发得相当快,因此您可以平滑地调整图标大小。而且它们只会在识别出的捏合事件时触发 - 因此它们不会在滚动事件期间触发。

调用的操作方法必须符合以下签名之一:

- (void)handleGesture;- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;

您必须小心不要覆盖地图的默认缩放行为。有关更多信息,请参阅此帖子:“UIMapView:未调用 UIPinchGestureRecognizer”。简短的回答是您必须实现 shouldRecognizeSimultaneouslyWithGestureRecognizer: 并返回 YES。

这里说的是一些示例代码:

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad

    [super viewDidLoad];

    self.mapView.mapType = MKMapTypeStandard;   // also MKMapTypeSatellite or MKMapTypeHybrid

    // Add a pinch gesture recognizer
    UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)];
    pinchRecognizer.delegate = self;
    [self.mapView addGestureRecognizer:pinchRecognizer];
    [pinchRecognizer release];


#pragma mark -
#pragma mark UIPinchGestureRecognizer

- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinchRecognizer 
    if (pinchRecognizer.state != UIGestureRecognizerStateChanged) 
        return;
    

    MKMapView *aMapView = (MKMapView *)pinchRecognizer.view;

    for (id <MKAnnotation>annotation in aMapView.annotations) 
        // if it's the user location, just return nil.
        if ([annotation isKindOfClass:[MKUserLocation class]])
            return;

        // handle our custom annotations
        //
        if ([annotation isKindOfClass:[MKPointAnnotation class]])
        
            // try to retrieve an existing pin view first
            MKAnnotationView *pinView = [aMapView viewForAnnotation:annotation];
            //Format the pin view
            [self formatAnnotationView:pinView forMapView:aMapView];
        
        


- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
    return YES;

所以在这一点上 - 您再次有几个选项来调整注释的大小。以下两个代码示例都依赖于Troy Brant's code for getting the zoom level of an MKMapView。

    使用变换调整注释图像和标注的大小。就我个人而言,我认为转换会导致看起来更干净的调整大小。但在大多数情况下,不需要调整标注的大小。 仅调整注释图像的大小 - 我使用 Trevor Harmon's Resize a UIImage the right way,但我再次认为调整大小看起来并不那么干净。

这里还有一些示例代码:

- (void)formatAnnotationView:(MKAnnotationView *)pinView forMapView:(MKMapView *)aMapView 
    if (pinView)
    
        double zoomLevel = [aMapView zoomLevel];
        double scale = -1 * sqrt((double)(1 - pow((zoomLevel/20.0), 2.0))) + 1.1; // This is a circular scale function where at zoom level 0 scale is 0.1 and at zoom level 20 scale is 1.1

        // Option #1
        pinView.transform = CGAffineTransformMakeScale(scale, scale);

        // Option #2
        UIImage *pinImage = [UIImage imageNamed:@"YOUR_IMAGE_NAME_HERE"];
        pinView.image = [pinImage resizedImage:CGSizeMake(pinImage.size.width * scale, pinImage.size.height * scale) interpolationQuality:kCGInterpolationHigh];
    

如果可行,请不要忘记将其标记为答案。

【讨论】:

嘿。我会试试这个,谢谢你的好答案。而且不用担心批准:) 没错,ios6 上已经不行了。有人想出解决方案吗?【参考方案2】:

@Funktional 在 Swift 3 中的回答:

class MapViewController: UIViewController: UIGestureRecognizerDelegate 

    @IBOutlet weak var mapView: MKMapView!

    override func viewDidLoad() 
        super.viewDidLoad()

        // You can also add this gesture recognizer and set the delegate via storyboard
        let pinchGR = UIPinchGestureRecognizer(target: self, action: #selector(handlePinchGesture))
        pinchGR.delegate = self
        self.mapView.addGestureRecognizer(pinchGR)
    

    // link as @IBAction when added via storyboard
    func handlePinchGesture(_ sender: UIPinchGestureRecognizer) 
        if sender.state == .ended 
            for annotation in mapView.annotations 
                if annotation is MKUserLocation 
                    continue
                
                guard let annotationView = self.mapView.view(for: annotation) else  continue 
                let scale = -1 * sqrt(1 - pow(mapView.zoomLevel / 20, 2.0)) + 1.4
                annotationView.transform = CGAffineTransform(scaleX: CGFloat(scale), y: CGFloat(scale))
            
        
    

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool 
        return true
    


extension MKMapView 
    var zoomLevel: Double 
        return log2(360 * ((Double(self.frame.size.width) / 256) / self.region.span.longitudeDelta)) - 1
    

【讨论】:

【参考方案3】:

抱歉我的英语不好……但我只是想帮助别人。

非常感谢,Funktional。您的回答很棒……它在 iOS5 上完美运行!但是这在iOS6上失效了,目前看来没有解决这个问题的办法。

但最后,我以一种愚蠢/静态的方式解决了它,并且它在两个 iOS 上都可以正常工作。我不打算解释太多。这就是我在项目中所做的。

    mkannotation 的图像名为 pin.png(大小为 20x20)

    我为不同的缩放级别(18x18、16x16、14x14、12x12、10x10)创建了另外五张不同尺寸的图像,它们被命名为 pin-5.png、pin-4.png、pin-3.png , pin-2.png, pin-1.png.

    我删除了formatAnnotationView中所有关于计算比例的代码并添加了这一行

    NSString* imageName = 
        [NSString stringWithFormat:@"%@%@.png", 
        [imageName substringToIndex:[imageName length]-4 ], 
        [self getImageLevel]];
    

    另外,从

    UIImage *pinImage = [UIImage imageNamed:@"YOUR_IMAGE_NAME_HERE"];

    UIImage *pinImage = [[UIImage alloc] initWithContentsOfFile:imageName];

    添加此功能

    -(NSString *)getImageLevel
    
    NSString* output;
    
    double zoomLevel = [self getZoomLevel:_mapview];
    
    
    if(zoomLevel >= 19.0)
        output = @"";
    else if(zoomLevel < 19.0 && zoomLevel >= 18.0)
        output = @"-5";
    else if(zoomLevel < 18.0 && zoomLevel >= 17.0)
        output = @"-4";
    else if(zoomLevel < 17.0 && zoomLevel >= 16.0)
        output = @"-3";
    else if(zoomLevel < 16.0 && zoomLevel >= 15.0)
        output = @"-2";
    else 
        output = @"-1";
    
    return output;
    

再次对糟糕的编码和英语感到抱歉。

【讨论】:

【参考方案4】:

另一种方法是重新调整注释视图图像属性的大小。一个例子是shown in this post

【讨论】:

【参考方案5】:

在 Swift 3 中,这对我有用。我的图像在 19 级是 100%,所以 1/19 给了我 0.5263158,这是我的线性比例:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?     
  if annotation is MKUserLocation 
    return nil
  

  let mkView = MKAnnotationView(annotation: annotation, reuseIdentifier: "mkView")
  mkView.image = UIImage(named: "Foo")
  formatAnnotation(pinView: mkView, forMapView: mapView)
  return mkView;


func formatAnnotation(pinView: MKAnnotationView, forMapView: MKMapView) 
  let zoomLevel = forMapView.getZoomLevel()
  let scale = 0.05263158 * zoomLevel //Modify to whatever scale you need.
  pinView.transform = CGAffineTransform(scaleX: CGFloat(scale), y: CGFloat(scale))

【讨论】:

它仅适用于缩小时新创建的注释,已经创建的注释在缩小时大小不同,您有什么解决方案

以上是关于Resize MKAnnotationView Image 当地图放大和缩小时?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 MKAnnotationView 放置动画?

- (MKAnnotationView *)mapView 没有被调用

定位自定义 MKAnnotationView

MKAnnotationView 和点击检测

MKAnnotationView 自定义标注对辅助功能 (VoiceOver) 不可见

将 TintColor 设置为 MKAnnotationView 图像