Размер MKAnnotationView изображения, когда карта приближается и выходит?

что у меня есть

У меня около 150 MKAnnotationViews на карте. Каждый MKAnnotationView имеет изображение, которое заменяет pin-код по умолчанию.

что происходит

когда карта приближается, MKAnnotationViews становятся меньше и наоборот, когда она приближается.

что я хочу, чтобы произошло

Ну, я хочу, чтобы все было наоборот. С тех пор, как карта маленькая, я хочу, чтобы MKAnnotationViews будет меньше, чтобы пользователь мог видеть их все, и когда он увеличит масштаб, я хочу, чтобы они были больше.

какой код у меня до сих пор

Я знаю, как получить изменение масштаба, и я знаю, что могу получить "pMapView.регион.промежуток.latitudeDelta"в качестве ссылки на величину масштабирования. и я знаю, что могу изменить annotationView.рамка.

-(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];
    }
}

может кто-нибудь помочь мне с этим пожалуйста? спасибо Шани!--3-->

5 ответов


фактически на MKMapView по умолчанию-аннотация (например, pin или изображение) и выноска (например, пузырь) остаются того же размера, что и при увеличении или уменьшении масштаба. Они не масштабируются. Но я понимаю вашу точку зрения - по отношению к карте они, кажется, растут по мере увеличения карты и уменьшаются по мере увеличения карты.

Итак, есть два решения вашей проблемы и они работают немного по-другому:

  1. реализовать -(void)mapView:(MKMapView *)pMapView regionDidChangeAnimated:(BOOL)animated из ссылки на протокол MKMapViewDelegate-который ты уже сделал это.
  2. вложение UIPinchGestureRecognizer к объекту MKMapView, а затем реализовать действие.

Вариант #1 -mapView:regionDidChangeAnimated: будет вызываться для прокрутки или события масштабирования-в основном в любое время, когда область карты изменилась, как следует из названия. Это приводит к несколько менее плавному изменению размера значков, поскольку события карты запускаются реже.

мои предпочтения для опции #2-прикрепить UIPinchGestureRecognizer к объекту MKMapView, а затем реализовать действие. События Pinch gesture запускаются довольно быстро, поэтому вы получаете плавное изменение размера значка. И они срабатывают только для распознанного события щепотки-поэтому они не будут срабатывать во время события прокрутки.

вызываемые методы действия должны соответствовать одной из следующих сигнатур:

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

вы должны быть осторожны, чтобы не переопределить карты по умолчанию зум. См. это сообщение: "UIMapView: UIPinchGestureRecognizer не называется" для получения дополнительной информации. Короткий ответ заключается в том, что вы должны реализовать shouldRecognizeSimultaneouslyWithGestureRecognizer: и вернуться да.

все сказанное ниже приведен пример кода:

// 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;
}

на данный момент - у вас снова есть несколько вариантов как изменить размер аннотации. Оба следующих примера кода полагаются на код Троя Бранта для получения уровня масштабирования MKMapView.

  1. измените размер изображения аннотации и выноски с помощью преобразования. Лично я думаю, что преобразование приводит к более чистому изменению размера. Но в большинстве случаев-изменение размера выноски не требуется.
  2. изменить размер только изображения аннотации-я использую Тревор Хармон изменить размер UIImage правильный путь но, опять же, мое мнение, что это не так чисто, глядя на размер.

вот еще пример кода:

- (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];
    }
}

если это работает, не забудьте пометить его как ответ.


извините за мой плохой английский... но я просто хочу помочь кое-кому.

большое спасибо, Funktional. Ваш ответ великолепен... его работа на iOS5 отлично! Но это недействительно на iOS6, и, похоже, пока нет решения для решения этой проблемы.

но, наконец, я решил его глупым / статическим способом, и он отлично работает на обеих iOS. Я не собираюсь объяснять. Вот что я сделал в своем проекте.

  1. изображение mkannotation называется pin.png (размер 20x20)

  2. Я создал еще пять изображений с разным размером для разных уровней масштабирования (18x18, 16x16, 14x14, 12x12, 10x10), и они называются pin-5.ПНГ, пин-код-4.png, pin-3.png, pin-2.png, pin-1.формат PNG.

  3. Я удалил весь код о вычислении масштаба в formatAnnotationView и добавил эту строку

    NSString* imageName = 
        [NSString stringWithFormat:@"%@%@.png", 
        [imageName substringToIndex:[imageName length]-4 ], 
        [self getImageLevel]];
    
  4. кроме того, измените это с

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

    to

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

  5. добавить эту функцию

    -(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;}
    

извините за плохое кодирование и английский снова.


альтернативным методом будет изменение размера свойства изображения вида аннотации. Пример показано в этом посте


в Swift 3 это сработало для меня. Мое изображение было 100% на уровне 19, поэтому 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))
}

ответ@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
    }
}