Как я могу создать пользовательскую «пин-каплю» анимацию с использованием MKAnnotationView?

голоса
23

У меня есть экземпляр MKMapViewи хотел бы использовать пользовательские аннотаций иконки вместо стандартных значков контактов , поставляемых MKPinAnnotationView. Итак, я установка подкласс MKAnnotationView называется CustomMapAnnotation и я переопределение -(void)drawRect:рисовать CGImage. Это работает.

Проблема возникает , когда я пытаюсь повторить .animatesDropфункциональность поставляемого MKPinAnnotationView; Я хотел бы, чтобы мои значки появляются постепенно, упал сверху и слева-направо порядок, когда добавляются аннотация к MKMapViewпримеру.

Вот - (Недействительными) DrawRect: для CustomMapAnnotation, который работает, когда вы просто нарисовать UIImage (что делает вторая строка):

- (void)drawRect:(CGRect)rect {
 [super drawRect:rect];
 [((Incident *)self.annotation).smallIcon drawInRect:rect];
 if (newAnnotation) {
  [self animateDrop];
  newAnnotation = NO;
 }
} 

Проблема возникает , когда вы добавляете animateDropметод:

-(void)animateDrop {
 CGContextRef myContext = UIGraphicsGetCurrentContext();

 CGPoint finalPos = self.center;
 CGPoint startPos = CGPointMake(self.center.x, self.center.y-480.0);
 self.layer.position = startPos;

 CABasicAnimation *theAnimation;
 theAnimation=[CABasicAnimation animationWithKeyPath:@position];
 theAnimation.fromValue=[NSValue valueWithCGPoint:startPos];
 theAnimation.toValue=[NSValue valueWithCGPoint:finalPos];
 theAnimation.removedOnCompletion = NO;
 theAnimation.fillMode = kCAFillModeForwards;
 theAnimation.delegate = self;
 theAnimation.beginTime = 5.0 * (self.center.x/320.0);
 theAnimation.duration = 1.0;
 [self.layer addAnimation:theAnimation forKey:@];
}

Это просто не работает, и там может быть много причин, почему. Я не буду вдаваться во все из них в настоящее время. Главное я хотел бы знать, если подход звук вообще, или если я должен попробовать что-то совершенно другое.

Я пытался также упаковать все это в транзакции анимации, так что параметр BeginTime может сработать; это, казалось, ничего не делать вообще. Я не знаю, если это потому, что мне не хватает какой-то ключевой момент или является ли это потому, что MapKit будет громить мою анимацию каким-то образом.

  // Does nothing
  [CATransaction begin];
  [map addAnnotations:list];
  [CATransaction commit];

Если кто имеет опыт работы с анимированным MKMapAnnotations как это, я хотел бы некоторые советы, в противном случае, если вы можете дать совет CAAnimation на подходе, это было бы слишком большим.

Задан 07/12/2009 в 01:38
источник пользователем
На других языках...                            


5 ответов

голоса
58

Одна из проблем, с кодом Пола Шапиро в том, что он не имеет дело с тем, когда вы добавляете аннотации ниже, где пользователь смотрит в данный момент. Эти аннотации будут плавать в воздухе, прежде чем упасть, потому что они перемещаются в видимую карте прямоугольник пользователя.

Другим является то, что она также падает местоположение пользователя синяя точка. При этом коде ниже, вы регулируете как местоположение пользователя и большое количество карт аннотаций закадровых. Я также добавил хороший отскок;)

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
    MKAnnotationView *aV; 

    for (aV in views) {

        // Don't pin drop if annotation is user location
        if ([aV.annotation isKindOfClass:[MKUserLocation class]]) {
            continue;
        }

        // Check if current annotation is inside visible map rect, else go to next one
        MKMapPoint point =  MKMapPointForCoordinate(aV.annotation.coordinate);
        if (!MKMapRectContainsPoint(self.mapView.visibleMapRect, point)) {
            continue;
        }

        CGRect endFrame = aV.frame;

        // Move annotation out of view
        aV.frame = CGRectMake(aV.frame.origin.x, aV.frame.origin.y - self.view.frame.size.height, aV.frame.size.width, aV.frame.size.height);

        // Animate drop
        [UIView animateWithDuration:0.5 delay:0.04*[views indexOfObject:aV] options:UIViewAnimationCurveLinear animations:^{

            aV.frame = endFrame;

        // Animate squash
        }completion:^(BOOL finished){
            if (finished) {
                [UIView animateWithDuration:0.05 animations:^{
                    aV.transform = CGAffineTransformMakeScale(1.0, 0.8);

                }completion:^(BOOL finished){
                    [UIView animateWithDuration:0.1 animations:^{
                        aV.transform = CGAffineTransformIdentity;
                    }];
                }];
            }
        }];
    }
}
Ответил 12/08/2011 в 21:24
источник пользователем

голоса
52

Во-первых, вам нужно, чтобы сделать ваш контроллер представления реализации MKMapViewDelegate, если это не уже.

Затем реализовать этот метод:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views { 
   MKAnnotationView *aV; 
   for (aV in views) {
     CGRect endFrame = aV.frame;

     aV.frame = CGRectMake(aV.frame.origin.x, aV.frame.origin.y - 230.0, aV.frame.size.width, aV.frame.size.height);

     [UIView beginAnimations:nil context:NULL];
     [UIView setAnimationDuration:0.45];
     [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
         [aV setFrame:endFrame];
     [UIView commitAnimations];

   }
}

Добавьте аннотации к MapView и при их добавлении, этот метод делегата будет называться и оживят контакты сверху вниз, как они будут добавлены.

Значения времени и позиционирование могут быть изменено немного, но я подправил его, чтобы сделать его выглядеть лучше / ближе всего к традиционной капле (насколько я проверил). Надеюсь это поможет!

Ответил 18/01/2010 в 16:52
источник пользователем

голоса
12

С другой стороны , если вы делаете подкласс MKAnnotationView, вы можете использовать didMoveToSuperviewдля запуска анимации. Далее делает падение , которое заканчивается в небольшом «хлюпать» эффект

  #define kDropCompressAmount 0.1

  @implementation MyAnnotationViewSubclass

  ...

  - (void)didMoveToSuperview {
      CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
      animation.duration = 0.4;
      animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
      animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, -400, 0)];
      animation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];

      CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform"];
      animation2.duration = 0.10;
      animation2.beginTime = animation.duration;
      animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
      animation2.toValue = [NSValue valueWithCATransform3D:CATransform3DScale(CATransform3DMakeTranslation(0, self.layer.frame.size.height*kDropCompressAmount, 0), 1.0, 1.0-kDropCompressAmount, 1.0)];
      animation2.fillMode = kCAFillModeForwards;

      CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"transform"];
      animation3.duration = 0.15;
      animation3.beginTime = animation.duration+animation2.duration;
      animation3.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
      animation3.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
      animation3.fillMode = kCAFillModeForwards;

      CAAnimationGroup *group = [CAAnimationGroup animation];
      group.animations = [NSArray arrayWithObjects:animation, animation2, animation3, nil];
      group.duration = animation.duration+animation2.duration+animation3.duration;
      group.fillMode = kCAFillModeForwards;

      [self.layer addAnimation:group forKey:nil];
  }
Ответил 26/06/2010 в 19:56
источник пользователем

голоса
5

Для ответа Майкла Тайсона (я не могу комментировать везде еще), я предлагаю вставить следующий код в didMoveToSuperview для правильного повторного MKAnnotationView поэтому он делает анимацию, а затем снова имитировать sequencial добавление аннотаций

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

- (void)didMoveToSuperview {
    //necessary so it doesn't add another animation when moved to superview = nil
    //and to remove the previous animations if they were not finished!
    if (!self.superview) {
        [self.layer removeAllAnimations];
        return;
    }


    float xOriginDivider = 20.;
    float pos = 0;

    UIView *mySuperview = self.superview;
    while (mySuperview && ![mySuperview isKindOfClass:[MKMapView class]])
        mySuperview = mySuperview.superview;
    if ([mySuperview isKindOfClass:[MKMapView class]]) 
        //given the position in the array
        // pos = [((MKMapView *) mySuperview).annotations indexOfObject:self.annotation];   
        // left to right sequence;
        pos = [((MKMapView *) mySuperview) convertCoordinate:self.annotation.coordinate toPointToView:mySuperview].x / xOriginDivider;

    float yOffsetMultiplier = 20.;
    float timeOffsetMultiplier = 0.05;


    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
    animation.duration = 0.4 + timeOffsetMultiplier * pos;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, -400 - yOffsetMultiplier * pos, 0)];
    animation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];

    // rest of animation group...
}
Ответил 02/11/2010 в 11:08
источник пользователем

голоса
0

Я думаю, что лучшим вариантом будет установить «animatesDrop» ДА. Это свойство MKPinAnnotationView.

Ответил 10/11/2014 в 00:09
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more