Hvordan kan jeg lage en egendefinert "pin-drop" animasjon ved hjelp MKAnnotationView?

stemmer
23

Jeg har en forekomst av MKMapViewog ønsker å bruke tilpasset merknad ikoner i stedet for standard pinne ikonene levert av MKPinAnnotationView. Så, jeg har setup en underklasse av MKAnnotationView kalt CustomMapAnnotation og er overordnet -(void)drawRect:å tegne en CGImage. Dette fungerer.

Problemet kommer når jeg prøver å gjenskape den .animatesDropfunksjonalitet levert av MKPinAnnotationView; Jeg ville elske for mine ikoner til seg gradvis, falt ovenfra og fra venstre mot høyre for når merknadene er lagt til MKMapVieweksempel.

Her er - (void) drawRect: for CustomMapAnnotation, som fungerer når du bare trekke UIImage (som er hva andre linjen gjør):

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

Problemet kommer når du legger til animateDropmetoden:

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

Det virker bare ikke, og det kan være mange grunner til hvorfor. Jeg vil ikke komme inn på alle av dem nå. Det viktigste jeg ønsker å vite er om tilnærmingen er lyd i det hele tatt, eller om jeg bør prøve noe helt annet.

Jeg prøvde også å pakke opp hele greia i en animasjon transaksjonen, slik at beginTime parameter kan faktisk fungerer; dette syntes å ikke gjøre noe i det hele tatt. Jeg vet ikke om dette er fordi jeg mangler noen sentrale punkt, eller om det er fordi MapKit er å kaste mine animasjoner eller annen måte.

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

Hvis noen har noen erfaring med animerte MKMapAnnotations som dette, vil jeg gjerne noen hint, ellers hvis du kan tilby CAAnimation råd på tilnærming, det ville være flott også.

Publisert på 07/12/2009 klokken 00:38
kilden bruker
På andre språk...                            


5 svar

stemmer
58

Et problem med den koden ved Paul Shapiro er at den ikke forholde seg til når du legger til kommentarer under der brukeren er ute for øyeblikket. Disse kommentarene vil flyte i luften før slippe fordi de er flyttet inn i brukerens synlig kartet rect.

En annen er at det synker også brukerstedet blå prikk. Med denne koden nedenfor, håndtere du både bruker beliggenhet og store mengder kart merknader utenfor skjermen. Jeg har også lagt en fin sprett;)

- (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;
                    }];
                }];
            }
        }];
    }
}
Svarte 12/08/2011 kl. 20:24
kilden bruker

stemmer
52

Først må du gjøre ditt syn kontrolleren implementere MKMapViewDelegate hvis den ikke alt.

Deretter implementere denne metoden:

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

   }
}

Legg til merknader til MapView og når de er lagt, vil dette delegat metoden kalles, og vil animere pinnene fra topp til bunn som de legges.

Verdiene for timing og posisjonering kan bli endret litt, men jeg har forskjøvet det slik at den ser beste / nærmest tradisjonelle slipp (så vidt jeg har testet). Håper dette hjelper!

Svarte 18/01/2010 kl. 15:52
kilden bruker

stemmer
12

Alternativt, hvis du gjør en MKAnnotationView underklasse, kan du bruke didMoveToSuperviewtil å utløse animasjonen. I det følgende betyr en dråpe som ender i en liten 'squish' virkning

  #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];
  }
Svarte 26/06/2010 kl. 18:56
kilden bruker

stemmer
5

For Michael Tyson svar (jeg kan ikke kommentere overalt ennå), foreslår jeg en innsetting av følgende kode i didMoveToSuperview for riktig gjenbruk av MKAnnotationView så det gjør animasjonen igjen, og deretter imitere sequencial tilsetting av merknader

Lek med skillevegger og multiplikatorer for ulike visuelle resultater ...

- (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...
}
Svarte 02/11/2010 kl. 10:08
kilden bruker

stemmer
0

Jeg tror det beste alternativet er å sette 'animatesDrop' til YES. Det er en egenskap ved MKPinAnnotationView.

Svarte 10/11/2014 kl. 00:09
kilden bruker

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