Wie kann ich eine benutzerdefinierte „pin-drop“ Animation mit MKAnnotationView erstellen?

stimmen
23

Ich habe eine Instanz MKMapViewund möchten benutzerdefinierte Anmerkung Symbole verwenden , anstatt die Standard - Stift von MKPinAnnotationView geliefert Symbole. Also, ich habe Setup eine Unterklasse von MKAnnotationView genannt CustomMapAnnotation und ist überschreibt -(void)drawRect:eine CGImage zu ziehen. Das funktioniert.

Das Problem kommt , wenn ich versuche , die zu replizieren .animatesDropFunktionalität von MKPinAnnotationView geliefert; Ich würde gerne für meine Symbole allmählich erscheinen, von oben fallen gelassen und in von links nach rechts um, wenn die Anmerkungen zu den hinzugefügt werden MKMapViewInstanz.

Hier ist - (void) drawRect: für CustomMapAnnotation, die funktioniert, wenn Sie nur die UIImage ziehen (das ist, was die zweite Zeile der Fall ist):

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

Das Problem kommt , wenn Sie die Add - animateDropMethode:

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

Es funktioniert einfach nicht, und es könnte eine Menge Gründe, warum. Ich werde jetzt nicht in allen von ihnen bekommen. Die Hauptsache ich will ich wissen, ist, wenn der Ansatz Ton überhaupt, oder wenn ich etwas ganz anderes versuchen sollte.

Ich habe auch versucht, das Ganze in eine Animation Transaktion zu verpacken, so dass die Begintime Parameter könnten tatsächlich funktionieren; dies schien überhaupt nichts zu tun. Ich weiß nicht, ob dies ist, weil ich einige wichtige Punkt bin fehlt oder ob es ist, weil MapKit meine Animationen irgendwie Wegwerfen.

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

Wenn jemand irgendwelche Erfahrungen mit animierten MKMapAnnotations wie dieses hat, würde ich einige Hinweise lieben, sonst, wenn Sie CAAnimation Beratung auf dem Ansatz bieten kann, das wäre toll zu.

Veröffentlicht am 07/12/2009 um 01:38
quelle vom benutzer
In anderen Sprachen...                            


5 antworten

stimmen
58

Ein Problem mit dem Code von Paul Shapiro ist, dass es nicht mit sich umgehen, wenn Sie Anmerkungen hinzufügen unten, wo der Benutzer im Moment suchen. Diese Anmerkungen werden in der Luft schweben, bevor fallen, weil sie in den Benutzer sichtbar Karte rect bewegt werden.

Ein weiterer Grund ist, dass es auch den Benutzerstandort blauen Punkt fällt. Mit diesem Code unten, behandeln Sie sowohl Benutzerposition und große Mengen von Karte Anmerkungen Off-Screen. Außerdem habe ich einen schönen Bounce;)

- (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;
                    }];
                }];
            }
        }];
    }
}
Beantwortet am 12/08/2011 um 21:24
quelle vom benutzer

stimmen
52

Zuerst müssen Sie die Ansicht Controller machen MKMapViewDelegate implementieren, wenn es nicht bereits der Fall ist.

Dann implementieren diese Methode:

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

   }
}

Fügen Sie Ihre Anmerkungen zu den MapView und wenn sie hinzugefügt werden, werden diese Delegatmethode genannt werden und die Stifte von oben nach unten animieren, wie sie hinzugefügt werden.

Die Werte für Timing und Positionierung kann ein wenig geändert werden, aber ich habe es gezwickt es am besten / am nächsten zu dem traditionellen Tropfen aussehen (soweit ich getestet habe). Hoffe das hilft!

Beantwortet am 18/01/2010 um 16:52
quelle vom benutzer

stimmen
12

Alternativ, wenn Sie eine MKAnnotationView Unterklasse machen, können Sie didMoveToSuperviewdie Animation auszulösen. Im Folgenden macht einen Tropfen, der in einem leichten "Quetsch - Effekt " endet

  #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];
  }
Beantwortet am 26/06/2010 um 19:56
quelle vom benutzer

stimmen
5

Für Michael Tyson Antwort (ich kann nicht überall noch Kommentar), habe ich eine Einfügung des folgenden Codes in didMoveToSuperview für eine Wiederverwendung von MKAnnotationView vorschlagen, damit es die Animation wieder tut und imitieren dann die sequentielle Zugabe von Annotationen

Spielen Sie mit den Teilern und Multiplikatoren für verschiedene visuelle Ergebnisse ...

- (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...
}
Beantwortet am 02/11/2010 um 11:08
quelle vom benutzer

stimmen
0

Ich denke, die bessere Option ‚animatesDrop‘ auf YES gesetzt ist. Es ist eine Eigenschaft von MKPinAnnotationView.

Beantwortet am 10/11/2014 um 00:09
quelle vom benutzer

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