Pulse ring animation around a Google Maps marker iOS
Asked Answered
T

1

6

I want to add a pulse ring animation around a marker as a current user location in iOS google maps (like Uber). I tried with adding CABasicAnimation to marker layer by addAnimation. It is not working.

Also I tried animate the scale of the marker but the scale change did not happen. Can anybody help me with this thing?

Televise answered 16/12, 2016 at 12:48 Comment(2)
Post your current code along with information about how it behaves. "It is not working" is not very informative.Inconsumable
@DuncanC the code I updated as a answer now. Thank you!Televise
T
21

somehow it is working now. I created a custom view and set that view into GMSMarker iconView. After that added animation into view layer.

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(200, 200, 100, 100)];
view.backgroundColor = [UIColor redColor];
view.layer.cornerRadius = 50;

GMSMarker *m = [GMSMarker markerWithPosition:mapView_.myLocation.coordinate];
m.iconView = view;
m.map = mapView_;


CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation.duration = 1.5;
scaleAnimation.repeatCount = HUGE_VAL;
scaleAnimation.autoreverses = YES;
scaleAnimation.fromValue = [NSNumber numberWithFloat:0.1];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.2];

[view.layer addAnimation:scaleAnimation forKey:@"scale"];

Another method:


GMSMarker *m = [GMSMarker markerWithPosition:mapView_.myLocation.coordinate];

//custom marker image
    UIImageView *pulseRingImg = [[UIImageView alloc] initWithFrame: CGRectMake(-30, -30, 78, 78)];
    pulseRingImg.image = [UIImage imageNamed:@"Pulse"];
    pulseRingImg.userInteractionEnabled = NO;


    //transform scale animation
    CABasicAnimation *theAnimation;
    theAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.xy"];
    theAnimation.duration = 3.5;
    theAnimation.repeatCount = HUGE_VALF;
    theAnimation.autoreverses = NO;
    theAnimation.fromValue = [NSNumber numberWithFloat:0.0];
    theAnimation.toValue = [NSNumber numberWithFloat:2.0];

//alpha Animation for the image
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
    animation.duration = 3.5;
    animation.repeatCount = HUGE_VALF;
    animation.values = [NSArray arrayWithObjects:
                       [NSNumber numberWithFloat:1.0],
                       [NSNumber numberWithFloat:0.5],
                       [NSNumber numberWithFloat:0.0], nil];
    animation.keyTimes = [NSArray arrayWithObjects:
                         [NSNumber numberWithFloat:0.0],
                         [NSNumber numberWithFloat:1.2],
                         [NSNumber numberWithFloat:3.5], nil];
    [pulseRingImg.layer addAnimation:animation forKey:@"opacity"];


    [pulseRingImg.layer addAnimation:theAnimation forKey:@"pulse"];
    pulseRingImg.userInteractionEnabled = NO;

    m.iconView = pulseRingImg;
    [m.layer addSublayer:pulseRingImg.layer];
    m.map = mapView_;
    m.groundAnchor = CGPointMake(0.5, 0.5);

Another one:

m = [GMSMarker markerWithPosition:mapView_.myLocation.coordinate];

    //custom marker image
    UIImageView *pulseRingImg = [[UIImageView alloc] initWithFrame: CGRectMake(-30, -30, 78, 78)];
    pulseRingImg.image = [UIImage imageNamed:@"Pulse"];
    pulseRingImg.userInteractionEnabled = NO;

    float duration = 3.5f;

    [CATransaction begin];
    [CATransaction setAnimationDuration: duration];

    //transform scale animation
    CABasicAnimation *theAnimation;
    theAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.xy"];
    theAnimation.repeatCount = HUGE_VALF;
    theAnimation.autoreverses = NO;
    theAnimation.fromValue = [NSNumber numberWithFloat:0.0];
    theAnimation.toValue = [NSNumber numberWithFloat:2.0];

    [pulseRingImg.layer addAnimation:theAnimation forKey:@"pulse"];
    pulseRingImg.userInteractionEnabled = NO;

    [CATransaction setCompletionBlock:^{
        //alpha Animation for the image
        CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
        animation.duration = duration;
        animation.repeatCount = HUGE_VALF;
        animation.values = [NSArray arrayWithObjects:
                            [NSNumber numberWithFloat:1.0],
                            [NSNumber numberWithFloat:0.0], nil];
        [m.iconView.layer addAnimation:animation forKey:@"opacity"];
    }];

    [CATransaction commit];

    m.iconView = pulseRingImg;
    [m.layer addSublayer:pulseRingImg.layer];
    m.map = mapView_;
    m.groundAnchor = CGPointMake(0.5, 0.5);

Swift 3.0 code is below NOTE: Change the duration based on your requirement

           let m = GMSMarker(position: camera.target)

            //custom marker image
            let pulseRingImg = UIImageView(frame: CGRect(x: -30, y: -30, width: 78, height: 78))
            pulseRingImg.image = UIImage(named: "Pulse")
            pulseRingImg.isUserInteractionEnabled = false
            CATransaction.begin()
            CATransaction.setAnimationDuration(3.5)

            //transform scale animation
            var theAnimation: CABasicAnimation?
            theAnimation = CABasicAnimation(keyPath: "transform.scale.xy")
            theAnimation?.repeatCount = Float.infinity
            theAnimation?.autoreverses = false
            theAnimation?.fromValue = Float(0.0)
            theAnimation?.toValue = Float(2.0)
            theAnimation?.isRemovedOnCompletion = false

            pulseRingImg.layer.add(theAnimation!, forKey: "pulse")
            pulseRingImg.isUserInteractionEnabled = false
            CATransaction.setCompletionBlock({() -> Void in

                //alpha Animation for the image
                let animation = CAKeyframeAnimation(keyPath: "opacity")
                animation.duration = 3.5
                animation.repeatCount = Float.infinity
                animation.values = [Float(2.0), Float(0.0)]
                m.iconView?.layer.add(animation, forKey: "opacity")
            })

            CATransaction.commit()
            m.iconView = pulseRingImg
            m.layer.addSublayer(pulseRingImg.layer)
            m.map = gmapView
            m.groundAnchor = CGPoint(x: 0.5, y: 0.5)

pulse Image: pulse image for animation

Televise answered 16/12, 2016 at 13:24 Comment(12)
I'm glad you found a solution. In order to make your code more modular you might think about making your pulsing view a custom subclass of GMSMarker. That would make it a drop in and more reusable. (And you should accept your answer once the system allows you to do so.)Inconsumable
@Duncan C, Thank you! Yes, I have to implement in that manner like reusable. If you can help me out with a sample code, in that mostly welcome.Televise
@bsm-2000 Swift 3.0 code is updated in the answer. Have a look on it!Televise
@AntonyRaphel Wow, It's working perfectly , thanks To muchYoakum
There is a typo in your answer. For Image name you have wrote "pluse" in your second method. But at all other places in your code you have used "pulse". Please make it similar. By the way your answer was helpful. ThanksCapitol
@Antony Raphel issue occur when set [CABasicAnimation animationWithKeyPath: @"transform.scale"] animation on icon view so view will vibrate(Shake)Subscription
after use this animation CPU LOAD 96% .Vern
@Harshil are you used this on Google Maps?Televise
@AntonyRaphel YesVern
@Harshil its due to that Google Maps load. Not because of this code. Thanks!Televise
@AntonyRaphel ok Thank You i have check without map and with map both this CPU load its not because of animationVern
Thank you so much. Such a great solution.Lemmon

© 2022 - 2024 — McMap. All rights reserved.