0

I have a CABasicAnimation that creates an iris wipe effect on an image. In short, the animation works fine on the simulator but there is no joy on device. The timers still fire correctly and the animationCompleted block gets called however there is no visible animation.

Here is the code to get the iris wipe working:

- (void)irisWipe
{
animationCompletionBlock theBlock;

_resultsImage.hidden = FALSE;//Show the image view
[_resultsImage setImage:[UIImage imageNamed:@"logoNoBoarder"]];
[_resultsImage setBackgroundColor:[UIColor clearColor]];
[_resultsImage setFrame:_imageView.bounds];

//Create a shape layer that we will use as a mask for the waretoLogoLarge image view
CAShapeLayer *maskLayer = [CAShapeLayer layer];

CGFloat maskHeight = _resultsImage.layer.bounds.size.height;
CGFloat maskWidth = _resultsImage.layer.bounds.size.width;

CGPoint centerPoint;
centerPoint = CGPointMake( maskWidth/2, maskHeight/2);

//Make the radius of our arc large enough to reach into the corners of the image view.
CGFloat radius = sqrtf(maskWidth * maskWidth + maskHeight * maskHeight)/2;
//  CGFloat radius = MIN(maskWidth, maskHeight)/2;

//Don't fill the path, but stroke it in black.
maskLayer.fillColor = [[UIColor clearColor] CGColor];
maskLayer.strokeColor = [[UIColor blackColor] CGColor];

maskLayer.lineWidth = radius; //Make the line thick enough to completely fill the circle we're drawing
// maskLayer.lineWidth = 10; //Make the line thick enough to completely fill the circle we're drawing

CGMutablePathRef arcPath = CGPathCreateMutable();

//Move to the starting point of the arc so there is no initial line connecting to the arc
CGPathMoveToPoint(arcPath, nil, centerPoint.x, centerPoint.y-radius/2);

//Create an arc at 1/2 our circle radius, with a line thickess of the full circle radius
CGPathAddArc(arcPath,
             nil,
             centerPoint.x,
             centerPoint.y,
             radius/2,
             3*M_PI/2,
             -M_PI/2,
             NO);

maskLayer.path = arcPath;

//Start with an empty mask path (draw 0% of the arc)
maskLayer.strokeEnd = 1.0;

CFRelease(arcPath);

//Install the mask layer into out image view's layer.
_resultsImage.layer.mask = maskLayer;

//Set our mask layer's frame to the parent layer's bounds.
_resultsImage.layer.mask.frame = _resultsImage.layer.bounds;

//Create an animation that increases the stroke length to 1, then reverses it back to zero.
CABasicAnimation *swipe = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
swipe.duration = 1;
swipe.delegate = self;
[swipe setValue: theBlock forKey: kAnimationCompletionBlock];

swipe.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
swipe.fillMode = kCAFillModeForwards;
swipe.removedOnCompletion = NO;
swipe.autoreverses = NO;

swipe.toValue = [NSNumber numberWithFloat: 0];

//Set up a completion block that will be called once the animation is completed.
theBlock = ^void(void)
{
    NSLog(@"completed");
};

[swipe setValue: theBlock forKey: kAnimationCompletionBlock];

// doingMaskAnimation = TRUE;
[maskLayer addAnimation: swipe forKey: @"strokeEnd"];

}

Is there something in iOS7 I should be aware of when working with CAAnimations etc? OR is there a error in the code?

Note this code was sourced from: How do you achieve a "clock wipe"/ radial wipe effect in iOS?

Community
  • 1
  • 1
Taylor Abernethy Newman
  • 1,162
  • 1
  • 11
  • 22
  • I don't see anything obvious wrong with your code. You've changed my code to start with the layer visible and make it animate away, but that should be fine. Is your view visible? What happens if you comment out the code that adds the shape layer as a mask of your view's layer? Is the view's image visible? – Duncan C Apr 01 '14 at 02:00
  • Thanks for the help Duncan, yes the view is visible, it is visible for the duration of the animation and then once the completion block is called it removes the view from the screen. So it is only the layered animation that does not work. I might convert your original to an iPhone app and run a test on device with that. – Taylor Abernethy Newman Apr 01 '14 at 02:21
  • Can you post a project that exhibits the problem on github and post a link here? I'll take a look. – Duncan C Apr 02 '14 at 02:26
  • 2
    Hey Taylor. If you've noticed this breaking on 64bit iOS devices, here is a fix for that: Replace "3*M_PI/2" with "M_PI * -90 / 180" and "-M_PI/2" with "M_PI * 270 / 180" it works fine in both 32 and 64 bit devices (and simulators) I like to think in degrees, so I'd actually use inlines for those values -- DEG2RAD(-90) and DEG2RAD(270): #define DEG2RAD(x) (x * M_PI / 180) #define RAD2DEG(x) (x * 180 / M_PI) – eric Apr 11 '14 at 19:54
  • Thanks @eric! I was wondering if it was the 64bit causing problems – Taylor Abernethy Newman Apr 14 '14 at 00:07
  • @eric can you explain what exactly you are changing here? Since you are still using the constant M_PI I don't see how one would work and the other wouldn't... – jowie Apr 16 '14 at 11:24
  • I'm finding that the `clockwise` property of `bezierPathWithArcCentre` can only be set to `YES` on 64-bit, which is a bit of a problem for me... – jowie Apr 16 '14 at 11:26
  • So it appears as though - for some reason - on a 64-bit system you have to ensure that the `startAngle` is _greater_ than the `endAngle` _if_ you are drawing an anti-clockwise path. – jowie Apr 16 '14 at 13:02
  • Sorry @jowie, as part of making myself understand it, I converted to my macros… which also swapped start and end to make the start angle -90 and the end +270. As you just said, start – eric Apr 16 '14 at 16:25

1 Answers1

1

I think the problem (or at least part of it) may be this line:

[_resultsImage setFrame:_imageView.bounds];

That should read

[_resultsImage setBounds:_imageView.bounds];

Instead. If you set the FRAME to the bounds of the image view, you're going to move the image view to 0.0 in its superview.

I'm also not clear what _imageView is, as opposed to _resultsImage.

I would step through your code in the debugger, looking at the frame rectangles that are being set for the image view and mask layer, and all the other values that are calculated.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Hey Duncan! Thanks for this :) Unfortunately I didn't have time to pursue this and had to put in a small animation sequence, however I ran a test on another project and it seems to be working with this code. Thank you again for you help! If there was an app that allowed me to buy you a box of beer on the other side of the world I defiantly would :) – Taylor Abernethy Newman Apr 03 '14 at 22:17
  • 1
    @TaylorAbernethyNewman, if there was such an app I'd **drink** that beer. :) – Duncan C Apr 04 '14 at 00:12