¿Cómo puedo crear una animación personalizada "pin-drop" usando MKAnnotationView?

votos
23

Tengo una instancia de MKMapViewy me gustaría utilizar iconos de anotación personalizados en lugar de los iconos de pin estándar suministrados por MKPinAnnotationView. Por lo tanto, configuré una subclase de MKAnnotationView llamada CustomMapAnnotation y anulo -(void)drawRect:para dibujar una CGImage. Esto funciona.

El problema surge cuando trato de replicar la .animatesDropfuncionalidad proporcionada por MKPinAnnotationView; Me encantaría que mis íconos aparezcan gradualmente, caídos desde arriba y en orden de izquierda a derecha, cuando las anotaciones se agregan alMKMapView instancia.

Aquí está - (void) drawRect: para CustomMapAnnotation, que funciona cuando se dibuja el UIImage (que es lo que hace la 2ª línea):

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

El problema surge cuando agrega el animateDropmétodo:

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

Simplemente no funciona, y podría haber muchas razones por las cuales. No voy a entrar en todos ellos ahora. Lo principal que quiero saber es si el enfoque es correcto o si debería intentar algo completamente diferente.

Intenté también empaquetar todo en una transacción de animación para que el parámetro beginTime realmente funcionara; esto parecía no hacer nada en absoluto. No sé si esto se debe a que me falta algún punto clave o si es porque MapKit está destruyendo mis animaciones de alguna manera.

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

Si alguien tiene alguna experiencia con MKMapAnnotations animadas como esta, me encantaría dar algunos consejos; de lo contrario, si puedes ofrecer consejos de CAAnimation sobre el enfoque, sería genial también.

Publicado el 07/12/2009 a las 01:38
fuente por usuario
En otros idiomas...                            


5 respuestas

votos
58

Un problema con el código de Paul Shapiro es que no se ocupa de anotaciones cuando se agrega debajo de donde el usuario está buscando en este momento. Estas anotaciones flotarán en el aire antes de caer, ya que se mueven en un mapa visible rect del usuario.

Otra es que también se reduce el punto azul ubicación del usuario. Con este código de abajo, que maneja tanto la ubicación del usuario y grandes cantidades de mapa anotaciones fuera de la pantalla. También he añadido un buen rebote;)

- (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;
                    }];
                }];
            }
        }];
    }
}
Respondida el 12/08/2011 a las 21:24
fuente por usuario

votos
52

En primer lugar, es necesario hacer que su controlador de vista implementar MKMapViewDelegate si no lo hace ya.

A continuación, poner en práctica este método:

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

   }
}

Añadir sus anotaciones al MapView y cuando se abonen, este método delegado se llamó y se animará los pasadores de arriba hacia abajo a medida que se añaden.

Los valores de tiempo y posicionamiento se pueden cambiar un poco, pero me han ajustado para que sea mejor mirar / más cercano a la caída tradicional (por lo que he probado). ¡Espero que esto ayude!

Respondida el 18/01/2010 a las 16:52
fuente por usuario

votos
12

Alternativamente, si usted está haciendo una subclase MKAnnotationView, se puede utilizar didMoveToSuperviewpara activar la animación. El siguiente no una gota que termina en un ligero efecto 'desplazamiento de la mezcla'

  #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];
  }
Respondida el 26/06/2010 a las 19:56
fuente por usuario

votos
5

Para la respuesta de Michael Tyson (que no puedo comentar todas partes aún), propongo una inserción del siguiente código en didMoveToSuperview para su reutilización adecuada de MKAnnotationView lo que hace la animación de nuevo y luego imitar la adición secuencial de las anotaciones

Juega con los divisores y multiplicadores para diferentes resultados visuales ...

- (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...
}
Respondida el 02/11/2010 a las 11:08
fuente por usuario

votos
0

Creo que la mejor opción es establecer 'animatesDrop' a SÍ. Es una propiedad de MKPinAnnotationView.

Respondida el 10/11/2014 a las 00:09
fuente por usuario

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