Search code examples
ioscore-animation

Getting a wave like animation in concentric circles in ios


I have this need to display two points emitting signals. The way the signals is represented is the wifi signal strength indicator that we commonly see in Macs.

However, there are a couple of changes to that:

  1. It is inverted. The source is pointed at top. Look at the image below:
  2. And I need to animate the lines to give the indication that the source is emitting signal.

image

I was able to get the attached images by overriding the drawRect of the View class:

CGContext context = UIGraphics.GetCurrentContext();
context.SetLineWidth(2.0f);

UIColor color = UIColor.FromRGB(65, 137, 77); 
context.SetStrokeColorWithColor(color.CGColor);

float maxRadius = rect.Height; 
const float delta = 15; 
float Y = center.Y; 
for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= delta) {              
    context.AddArc(center.X, Y, currentRadius, -ToRadians(startAngle), -ToRadians(endAngle), true);
    context.StrokePath(); 
}

I'm out of my depths here. If someone can point me to the right direction, that would be super awesome!


Solution

  • I took a shot at this using Core Animation. I just add a shape layer with a circle shape for each of the waves and then dynamically adjust their strokeStart and strokeEnd properties to get it to vary the width of each wave. So the output is like this:

    enter image description here

    Here is the initialization code:

    - (void)addWavesToView
    {
        CGRect rect = CGRectMake(0.0f, 0.0f, 300.0f, 300.0f);
        UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:rect];
    
        for (NSInteger i = 0; i < 10; ++i) {
            CAShapeLayer *waveLayer = [CAShapeLayer layer];
            waveLayer.bounds = rect;
            waveLayer.position = CGPointMake(300.0f, 100.0f);
            waveLayer.strokeColor = [[UIColor lightGrayColor] CGColor];
            waveLayer.fillColor = [[UIColor clearColor] CGColor];
            waveLayer.lineWidth = 5.0f;
            waveLayer.path = circlePath.CGPath;
    
            // Translate on the y axis to shift all the layers down while
            // we're creating them. Could do this with the position value as well
            // but this is a little cleaner.
            waveLayer.transform = CATransform3DMakeTranslation(0.0f, i*25, 0.0f);
    
            // strokeStart begins at 3:00. You would need to transform (rotate)
            // the layer 90 deg CCW to have it start at 12:00
            waveLayer.strokeStart = 0.25 - ((i+1) * 0.01f);
            waveLayer.strokeEnd = 0.25 + ((i+1) * 0.01f);
    
            [self.view.layer addSublayer:waveLayer];
        }
    }
    

    And then here is where I add the animations for each layer:

    - (void)addAnimationsToLayers
    {
        NSInteger timeOffset = 10;
        for (CALayer *layer in self.view.layer.sublayers) {
            CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeColor"];
            animation.duration = 10.0f;
    
            // Stagger the animations so they don't begin until the
            // desired time in each
            animation.timeOffset = timeOffset--;
            animation.toValue = (id)[[UIColor lightGrayColor] CGColor];
            animation.fromValue = (id)[[UIColor darkGrayColor] CGColor];
    
            // Repeat forever
            animation.repeatCount = HUGE_VALF;
    
            // Run it at 10x. You can adjust this to taste.
            animation.speed = 10;
    
            // Add to the layer to start the animation
            [layer addAnimation:animation forKey:@"strokeColor"];
        }
    
    }
    

    I posted it to github. Not sure if it's exactly what you're looking for, but hopefully it points you in the right direction.