Come posso creare un'animazione personalizzata "pin-drop" utilizzando MKAnnotationView?

voti
23

Ho un'istanza di MKMapViewe vorrei usare le icone di annotazione personalizzati invece delle icone pin standard fornite da MKPinAnnotationView. Così, Ho installato una sottoclasse di MKAnnotationView chiamato CustomMapAnnotation e sto override -(void)drawRect:per disegnare un CGImage. Questo funziona.

Il problema arriva quando si tenta di replicare la .animatesDropfunzionalità fornita da MKPinAnnotationView; Mi piacerebbe per le mie icone di apparire poco a poco, lasciato cadere dall'alto e in sinistra a destra ordine, quando le annotazioni si aggiungono alla MKMapViewistanza.

Ecco - (void) drawRect: per CustomMapAnnotation, che funziona solo quando si disegna l'UIImage (che è ciò che il 2 ° riga fa):

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

Il problema arriva quando si aggiunge il animateDropmetodo:

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

Semplicemente non funziona, e ci potrebbe essere un sacco di motivi. Non voglio entrare in tutti loro ora. La cosa principale Sono voler sapere è se l'approccio è suono a tutti, o se devo provare qualcosa di completamente diverso.

Ho cercato anche di confezionare il tutto in una transazione di animazione in modo che il parametro BEGINTime potrebbe effettivamente funzionare; questo sembrava non fare nulla. Non so se questo è perché mi manca un certo punto chiave o se è perché è MapKit cestinare mie animazioni in qualche modo.

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

Se qualcuno ha qualche esperienza con MKMapAnnotations animati come questo, mi piacerebbe alcuni suggerimenti, altrimenti se si può offrire consigli CAAnimation sull'approccio, che sarebbe troppo grande.

È pubblicato 07/12/2009 alle 01:38
fonte dall'utente
In altre lingue...                            


5 risposte

voti
58

Un problema con il codice di Paul Shapiro è che non si tratta di quando si aggiungono annotazioni sotto dove l'utente sta guardando in quel momento. Tali annotazioni galleggia a mezz'aria prima di cadere, perché sono spostati in mappa visibile rect dell'utente.

Un altro è quello che cade anche la posizione dell'utente puntino blu. Con questo codice di seguito, a gestire sia posizione dell'utente e grandi quantità di carta annotazioni off-screen. Ho anche aggiunto un bel rimbalzo;)

- (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;
                    }];
                }];
            }
        }];
    }
}
Risposto il 12/08/2011 a 21:24
fonte dall'utente

voti
52

In primo luogo, è necessario per rendere il vostro controller di vista implementare MKMapViewDelegate se non lo fa già.

Poi, implementare questo metodo:

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

   }
}

Aggiungere le annotazioni al MapView e quando vengono aggiunti, questo metodo delegato sarà chiamato e animerà i pin da cima a fondo come sono aggiunti.

I valori di sincronizzazione e posizionamento possono essere cambiati un po 'ma ho ottimizzato per farlo sembrare migliore / più vicino alla caduta tradizionale (per quanto ho provato). Spero che questo ti aiuti!

Risposto il 18/01/2010 a 16:52
fonte dall'utente

voti
12

In alternativa, se stai facendo una sottoclasse MKAnnotationView, è possibile utilizzare didMoveToSuperviewper attivare l'animazione. Quanto segue fa una goccia che termina con un leggero effetto 'squish'

  #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];
  }
Risposto il 26/06/2010 a 19:56
fonte dall'utente

voti
5

Per la risposta di Michael Tyson (non posso commentare in tutto il mondo ancora), vi propongo un inserimento del seguente codice nel didMoveToSuperview per il corretto riutilizzo dei MKAnnotationView così lo fa ancora una volta l'animazione e poi imiti la sequenziale aggiunta di annotazioni

Gioca con i divisori e moltiplicatori per i diversi risultati visivi ...

- (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...
}
Risposto il 02/11/2010 a 11:08
fonte dall'utente

voti
0

Credo che la soluzione migliore è quella di impostare 'animatesDrop' su YES. Si tratta di una proprietà di MKPinAnnotationView.

Risposto il 10/11/2014 a 00:09
fonte dall'utente

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