Search code examples
core-animationgoogle-maps-sdk-ios

Animating GMSMarker in a circular path


I understand how to normally animation other CALayers in a circular path based on this SO question: iPhone - How to make a circle path for a CAKeyframeAnimation?

However, the GMSMarkerLayer is a special subclass of CALayers that does not seem to respond to the "position" keypath (following instructions in that link does nothing that I can visibly see) but instead will respond to the "latitude" and "longitude" keypaths instead.

Here's the code that I've tried:

CAKeyframeAnimation *circlePathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
CGMutablePathRef circularPath = CGPathCreateMutable();
CGRect pathRect = CGRectMake(marker.position.latitude, marker.position.longitude, 0.001, 0.001);
CGPathAddEllipseInRect(circularPath, NULL, pathRect);
circlePathAnimation.path = circularPath;
circlePathAnimation.duration = 1.0f;
circlePathAnimation.repeatCount = HUGE_VALF;

[marker.layer addAnimation:circlePathAnimation forKey:[NSString stringWithFormat:@"circular-%@", marker.description]];
CGPathRelease(circularPath);

Since the keyframe animation will use the "position" keypath, how can I convert that into 2 separate keypaths (latitude and longitude) so I can animate the marker in a circle on the map?

Any help is greatly appreciated.


Solution

  • As currently I cannot use the "position" keypath for animating, I ended up animating it using the "latitude" and "longitude" keypaths separately.

    First calculate the points and add them to 2 separate arrays, one for latitude value (y) and one for longitude (x) and then use the values property in CAKeyFrameAnimation to animate. Create 2 CAKeyFrameAnimation objects (1 for each axis) and group them together using CAAnimationGroup and animate them together to form a circle.

    In my equation I vary the length of the radius on each axis so that I can also generate an oval path.

        NSMutableArray *latitudes = [NSMutableArray arrayWithCapacity:21];
        NSMutableArray *longitudes = [NSMutableArray arrayWithCapacity:21];
        for (int i = 0; i <= 20; i++) {
            CGFloat radians = (float)i * ((2.0f * M_PI) / 20.0f);
    
            // Calculate the x,y coordinate using the angle
            CGFloat x = hDist * cosf(radians);
            CGFloat y = vDist * sinf(radians);
    
            // Calculate the real lat and lon using the
            // current lat and lon as center points.
            y = marker.position.latitude + y;
            x = marker.position.longitude + x;
    
    
            [longitudes addObject:[NSNumber numberWithFloat:x]];
            [latitudes addObject:[NSNumber numberWithFloat:y]];
        }
    
        CAKeyframeAnimation *horizontalAnimation = [CAKeyframeAnimation animationWithKeyPath:@"longitude"];
        horizontalAnimation.values = longitudes;
        horizontalAnimation.duration = duration;
    
        CAKeyframeAnimation *verticleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"latitude"];
        verticleAnimation.values = latitudes;
        verticleAnimation.duration = duration;
    
        CAAnimationGroup *group = [[CAAnimationGroup alloc] init];
        group.animations = @[horizontalAnimation, verticleAnimation];
        group.duration = duration;
        group.repeatCount = HUGE_VALF;
        [marker.layer addAnimation:group forKey:[NSString stringWithFormat:@"circular-%@",marker.description]];