Cum pot crea un obicei „pin-drop“ animație folosind MKAnnotationView?

voturi
23

Am un exemplu de MKMapViewși - ar dori să utilizeze pictogramele personalizate de adnotare în loc de pictogramele standard pini furnizate de MKPinAnnotationView. Deci, am setup - o subclasă a MKAnnotationView numit CustomMapAnnotation și sunt imperative -(void)drawRect:pentru a desena un CGImage. Acest lucru funcționează.

Problema vine atunci când încerc să reproducă .animatesDropfuncționalitatea furnizate de MKPinAnnotationView; Mi - ar plăcea pictogramele mele să apară treptat, a scăzut de la mai sus și în stânga la dreapta ordine, atunci când adnotările sunt adăugate la MKMapViewinstanță.

Aici este - (void) drawRect: pentru CustomMapAnnotation, care funcționează atunci când doar trage UIImage (care este ceea ce face linia a 2):

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

Problema vine atunci când adăugați animateDropmetoda:

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

Pur și simplu nu funcționează, și ar putea exista o mulțime de motive. Nu voi intra în toate dintre ele acum. Principalul lucru pe care eu doresc să știu este dacă abordarea este un sunet, sau dacă ar trebui să încerc ceva cu totul diferit.

Am încercat, de asemenea, la pachet cu totul într-o tranzacție de animație, astfel încât parametrul beginTime ar putea să funcționeze efectiv; acest lucru părea să nu facă nimic. Nu știu dacă acest lucru se datorează faptului că eu sunt lipsesc unele punct-cheie sau dacă este pentru că MapKit este trashing animații mele într-un fel.

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

Dacă cineva are nici o experiență cu MKMapAnnotations animate, cum ar fi acest lucru, mi-ar plăcea câteva sugestii, în caz contrar, dacă vă poate oferi sfaturi CAAnimation cu privire la modul de abordare, care ar fi prea mare.

Întrebat 07/12/2009 la 01:38
sursa de către utilizator
În alte limbi...                            


5 răspunsuri

voturi
58

O problemă cu codul de Paul Shapiro este că nu se face cu atunci când adăugați adnotări de mai jos în cazul în care utilizatorul se uită la acest moment. Aceste adnotări vor pluti în aer la mijlocul înainte de a scădea, deoarece acestea sunt mutate în harta RECT vizibile utilizatorului.

Un alt aspect este faptul că scade, de asemenea, locația utilizatorului punctul albastru. Cu acest cod de mai jos, vă ocupa atât locația utilizatorului și cantități mari de hartă adnotări-off ecran. Am adăugat, de asemenea, un salt frumos;)

- (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;
                    }];
                }];
            }
        }];
    }
}
Publicat 12/08/2011 la 21:24
sursa de către utilizator

voturi
52

În primul rând, trebuie să vă controlerul de vedere punerea în aplicare a MKMapViewDelegate dacă nu deja.

Apoi, pune în aplicare această metodă:

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

   }
}

Adăugați adnotări dvs. la MapView și atunci când acestea se adaugă, această metodă delegat va fi numit și va anima pinii de sus în jos, deoarece acestea sunt adăugate.

Valorile pentru calendarul și poziționare poate fi schimbat un pic, dar l-am optimizat pentru a face sa arate cel mai bine / cel mai apropiat de meniurile tradiționale (în măsura în care am testat). Sper că acest lucru vă ajută!

Publicat 18/01/2010 la 16:52
sursa de către utilizator

voturi
12

De asemenea, dacă faci o subclasă MKAnnotationView, puteți utiliza didMoveToSuperviewpentru a declanșa animație. Următoarele face o picătură care se termină într - un ușor efect de „strivi“

  #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];
  }
Publicat 26/06/2010 la 19:56
sursa de către utilizator

voturi
5

Pentru răspunsul lui Michael Tyson (nu pot comenta peste tot încă), propun o inserție a următorul cod în didMoveToSuperview pentru reutilizarea adecvată a MKAnnotationView astfel încât o face din nou animația și apoi imita adăugarea secvențială de adnotări

Joaca-te cu separatoare și multiplicatori pentru rezultate vizuale diferite ...

- (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...
}
Publicat 02/11/2010 la 11:08
sursa de către utilizator

voturi
0

Cred că cea mai bună opțiune este de a stabili „animatesDrop“ la YES. Este o proprietate de MKPinAnnotationView.

Publicat 10/11/2014 la 00:09
sursa de către utilizator

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