24

のインスタンスがMKMapViewあり、MKPinAnnotationView によって提供される標準のピン アイコンの代わりにカスタムの注釈アイコンを使用したいと考えています。そのため、CustomMapAnnotation と呼ばれる MKAnnotationView のサブクラスをセットアップし、CGImage-(void)drawRect:を描画するためにオーバーライドしています。これは機能します。

.animatesDropMKPinAnnotationView によって提供される機能を複製しようとすると、問題が発生します。注釈がMKMapViewインスタンスに追加されると、アイコンが上から左から右の順にドロップされて徐々に表示されることを望みます。

ここに -(void)drawRect: があります: CustomMapAnnotation の場合、UIImage を描画するだけで機能します (これは 2 行目です)。

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

animateDropメソッドを追加すると問題が発生します。

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

うまくいかないだけで、多くの理由が考えられます。今はそれらすべてには立ち入りません。私が知りたい主なことは、アプローチがまったく正しいかどうか、またはまったく別のことを試す必要があるかどうかです。

また、beginTime パラメーターが実際に機能するように、すべてをアニメーション トランザクションにパッケージ化しようとしました。これはまったく何もしていないように見えました。これは、重要なポイントが欠けているためなのか、それとも MapKit が何らかの方法でアニメーションを台無しにしているからなのかはわかりません。

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

このようなアニメーション化された MKMapAnnotations を使用した経験がある場合は、いくつかのヒントが欲しいです。それ以外の場合は、アプローチに関する CAAnimation のアドバイスを提供できれば、それも素晴らしいことです。

4

5 に答える 5

58

Paul Shapiro によるコードの問題の 1 つは、ユーザーが現在見ている場所の下に注釈を追加するときに処理されないことです。これらの注釈は、ドロップする前に空中に浮かびます。これは、ユーザーの目に見える地図の四角形に移動されるためです。

もう1つは、ユーザーの場所の青い点もドロップすることです. 以下のコードを使用すると、ユーザーの位置情報と大量のマップ アノテーションの両方を画面外で処理できます。素敵なバウンスも追加しました ;)

- (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;
                    }];
                }];
            }
        }];
    }
}
于 2011-08-12T20:24:21.977 に答える
52

First, you need to make your view controller implement MKMapViewDelegate if it doesn't already.

Then, implement this method:

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

   }
}

Add your annotations to the MapView and when they are added, this delegate method will be called and will animate the pins from top to bottom as they are added.

The values for timing and positioning can be changed a little bit but I've tweaked it to make it look best/closest to the traditional drop (as far as I've tested). Hope this helps!

于 2010-01-18T15:52:33.397 に答える
12

または、MKAnnotationViewサブクラスを作成している場合は、を使用didMoveToSuperviewしてアニメーションをトリガーできます。以下は、わずかな「スキッシュ」効果で終わるドロップを行います

  #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];
  }
于 2010-06-26T18:56:04.363 に答える
5

Michael Tysonの応答(まだどこにもコメントできません)については、MKAnnotationViewを適切に再利用するために、didMoveToSuperviewに次のコードを挿入して、アニメーションを再度実行し、注釈の順次追加を模倣することを提案します。

さまざまな視覚的結果を得るために、分周器と乗数を試してみてください...

- (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...
}
于 2010-11-02T10:08:56.020 に答える
0

「animatesDrop」を YES に設定するのがより良いオプションだと思います。MKPinAnnotationView のプロパティです。

于 2014-11-10T00:09:15.710 に答える