Comment puis-je créer une coutume « goutte de pin » animation à l'aide MKAnnotationView?

voix
23

J'ai une instance de MKMapViewet je voudrais utiliser des icônes d'annotation personnalisée au lieu des icônes de broches standard fournis par MKPinAnnotationView. Donc, j'ai installé une sous - classe de MKAnnotationView appelé CustomMapAnnotation et je suis PRÉPONDÉRANTS -(void)drawRect:de tirer un CGImage. Cela marche.

Le problème vient quand je tente de reproduire la .animatesDropfonctionnalité fournie par MKPinAnnotationView; J'aimerais que mes icônes apparaissent peu à peu, larguée d' en haut et pour à droite à gauche, lorsque les annotations sont ajoutées à l' MKMapViewinstance.

Voici - (void) drawRect: pour CustomMapAnnotation, qui fonctionne lorsque vous dessinez la UIImage (qui est ce que la 2ème ligne fait):

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

Le problème vient quand vous ajoutez la animateDropméthode:

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

Il ne fonctionne pas seulement, et il pourrait y avoir beaucoup de raisons. Je ne vais pas entrer dans tous maintenant. La principale chose que je voulais savoir est si l'approche est de son du tout, ou si je devais essayer quelque chose de tout à fait différent.

J'ai aussi essayé d'emballer le tout dans une opération d'animation afin que le paramètre BeginTime pourrait en fait travailler; cela semblait ne rien faire du tout. Je ne sais pas si cela est parce que je manque un point clé ou que ce soit parce que MapKit est bousiller mes animations en quelque sorte.

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

Si quelqu'un a une expérience avec MKMapAnnotations animés comme cela, j'aimerais quelques conseils, sinon, si vous pouvez offrir CAAnimation des conseils sur l'approche, ce serait génial aussi.

Créé 07/12/2009 à 01:38
source utilisateur
Dans d'autres langues...                            


5 réponses

voix
58

Un problème avec le code par Paul Shapiro est qu'il ne traite pas lorsque vous ajoutez des annotations ci-dessous où l'utilisateur est à la recherche pour le moment. Ces annotations flottent dans l'air avant de tomber, car ils sont déplacés dans rect carte visible de l'utilisateur.

Une autre est qu'il diminue également l'emplacement de l'utilisateur point bleu. Avec ce code ci-dessous, vous gérez à la fois l'emplacement de l'utilisateur et de grandes quantités d'annotations cartographiques hors écran. J'ai aussi ajouté un beau rebond;)

- (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;
                    }];
                }];
            }
        }];
    }
}
Créé 12/08/2011 à 21:24
source utilisateur

voix
52

Tout d'abord, vous devez faire de votre contrôleur de vue de mettre en œuvre MKMapViewDelegate si elle n'a pas déjà.

Ensuite, mettre en œuvre cette méthode:

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

   }
}

Ajoutez vos annotations au MapView et quand ils sont ajoutés, cette méthode déléguée sera appelée et animer les broches de haut en bas comme ils sont ajoutés.

Les valeurs de synchronisation et de positionnement peuvent être modifiés un peu mais j'ai peaufiné pour le faire paraître plus / le plus proche de la chute traditionnelle (pour autant que je l'ai testé). J'espère que cela t'aides!

Créé 18/01/2010 à 16:52
source utilisateur

voix
12

Sinon, si vous faites une sous - classe MKAnnotationView, vous pouvez utiliser didMoveToSuperviewpour déclencher l'animation. Ce qui suit fait une chute qui se termine par un léger effet « Ecraser »

  #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];
  }
Créé 26/06/2010 à 19:56
source utilisateur

voix
5

Pour la réponse de Michael Tyson (je ne peux pas commenter partout encore), je vous propose une insertion du code suivant dans didMoveToSuperview pour une réutilisation de MKAnnotationView il fait nouveau l'animation puis imiter l'ajout d'annotations séquentiel

Jouez avec les séparateurs et multiplicateurs pour différents résultats visuels ...

- (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...
}
Créé 02/11/2010 à 11:08
source utilisateur

voix
0

Je pense que la meilleure option est de mettre « animatesDrop » YES. Il est une propriété de MKPinAnnotationView.

Créé 10/11/2014 à 00:09
source utilisateur

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