Powered By Blogger
Showing posts with label CGPathMoveToPoint. Show all posts
Showing posts with label CGPathMoveToPoint. Show all posts

Monday, October 1, 2012

Mask animation in iPhone

Hi,
Here is the sample code for "Mask Animation" in Objective C and iPhone/iPad/iPod.

#import <UIKit/UIKit.h>

typedef void (^animationCompletionBlock)(void);
#define kAnimationCompletionBlock @"animationCompletionBlock"

@interface ViewController : UIViewController
{
  BOOL animationInFlight;
  IBOutlet UIImageView *imageView;
}
@property (nonatomic) BOOL animationInFlight;

- (IBAction)MaskAnimation:(id)sender;


@end

#import <QuartzCore/QuartzCore.h>
#import "ViewController.h"



@interface ViewController ()

- (void) removePauseForLayer: (CALayer *) theLayer;
@end

@implementation ViewController


@synthesize animationInFlight;

#pragma mark - view lifecycle methods

- (void)viewDidLoad
{
  [super viewDidLoad];
}


//We only support portrait and portrait upside down orientations
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
  return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}


- (void)viewDidUnload
{
  imageView = nil;
  [super viewDidUnload];
  // Release any retained subviews of the main view.
}

#pragma mark - Instance methods

- (IBAction)MaskAnimation:(id)sender;
{
    animationCompletionBlock theBlock;
    imageView.hidden = FALSE;//Show the image view
   
    //Create a shape layer that we will use as a mask for the  image view
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
   
   
   
    CGFloat maskHeight = imageView.layer.bounds.size.height;
    CGFloat maskWidth = imageView.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 = 0.0;
   
   
    CFRelease(arcPath);
   
    //Install the mask layer into out image view's layer.
    imageView.layer.mask = maskLayer;
   
    //Set our mask layer's frame to the parent layer's bounds.
    imageView.layer.mask.frame = imageView.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 = 2;
    swipe.delegate = self;
    [swipe setValue: theBlock forKey: kAnimationCompletionBlock];
   
    swipe.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    swipe.fillMode = kCAFillModeForwards;
    swipe.removedOnCompletion = NO;
    swipe.autoreverses = YES;
   
    swipe.toValue = [NSNumber numberWithFloat: 1.0];
   
    self.animationInFlight = TRUE;
  
    //Set up a completion block that will be called once the animation is completed.
    theBlock = ^void(void)
    {   
        imageView.layer.mask = nil;
        self.animationInFlight = FALSE;
        imageView.hidden = TRUE;
       
        if (self.view.layer.speed == 0)
            [self removePauseForLayer: self.view.layer];
    };
   
    /*
     Install the completion block in the animation using the key kAnimationCompletionBlock
     The completion block will be run by in the animation's animationDidStop:finished delegate method.
     This approach doesn't work for animations that are part of a group, unfortunately, since an animation's
     delegate methods don't get called when the animation is part of an animation group
     */
   
    [swipe setValue: theBlock forKey: kAnimationCompletionBlock];
   
    [maskLayer addAnimation: swipe forKey: @"strokeEnd"];
   
}


- (void) removePauseForLayer: (CALayer *) theLayer;
{
    theLayer.speed = 1.0;
    theLayer.timeOffset = 0.0;
    theLayer.beginTime = 0.0;
}

#pragma mark - CAAnimation delegate methods

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
  animationCompletionBlock theBlock = [theAnimation valueForKey: kAnimationCompletionBlock];
  if (theBlock)
    theBlock();
}


@end