Showing posts with label CALayer. Show all posts
Showing posts with label CALayer. Show all posts

Sunday, 11 June 2017

Custom View With Transparent Oval.

UIBezierPath define a path consisting of straight and curved line segment and render the path in custom views. We can use this for specify the geometry of path, path can define simple shapes such as rectangle, oval, arc or can define complex polygons.For more details about UIBezierPath Click Here.

I am going to draw a custom view with transparent oval.I will use UIBenzierPath  fro achieving result.

First create a SubClass of UIView.
Ex. named sub class to CustomView
Inside drawRect: method of CustomView.m

- (void)drawRect:(CGRect)rect {
    // Drawing code

//First Create path for Oval
    UIBezierPath *apath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(5, 5,  self.frame.size.width-10, self.frame.size.height-10)];
    //Create another path
    UIBezierPath *clipPath = [ UIBezierPath bezierPathWithRect:CGRectInfinite];

//Append both path
    [clipPath appendPath:apath];
    clipPath.usesEvenOddFillRule = YES; //

usesEvenOddFillRule property is used to determine whether the even-odd or non-zero rule is used to determine the area enclosed by the path.   

  CGContextSaveGState(UIGraphicsGetCurrentContext());
    [clipPath addClip];
    CGContextSaveGState(UIGraphicsGetCurrentContext());
    [[UIColor orangeColor] setFill];
    [[UIColor blackColor] setStroke];
    clipPath.lineWidth = 2;
    [clipPath stroke];
    [clipPath fill];
}


Sunday, 4 June 2017

Core Animation

Core Animation is a graphics rendering and animation infrastructure use to animate the views and other visual elements. Core Animation is not a replacement for app’s views. Instead, it is a technology that integrates with views to provide better performance and support for animating their content. All you have to do is configure a few animation parameters (such as the start and end points) and tell Core Animation to start. Core Animation does the rest, handing most of the actual drawing work off to the onboard graphics hardware to accelerate the rendering. This automatic graphics acceleration results in high frame rates and smooth animations without burdening the CPU and slowing down your app.

Below code add "Pulse Effect" animation.

//Create a CALayer
CALayer *animatelayer = [CALayer layer];
//Setting Frame for CALayer
animatelayer.frame = CGRectMake(0,0, 160, 160);
//Setting Color for CALayer
animatelayer.backgroundColor = [UIColor redColor].CGColor;
//Setting Position for CALayer
animatelayer.position = (CGPoint){CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds)};
//Setting Corner radius for CALayer to look like a Circle
animatelayer.cornerRadius = 80;

//Create a Basic Animation
CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
theAnimation.duration=2.0;
theAnimation.repeatCount=HUGE_VALF;
theAnimation.autoreverses=YES;theAnimation.fromValue=[NSNumber numberWithFloat:0.7];
theAnimation.toValue=[NSNumber numberWithFloat:0.0];

//Add animation to CALayer
[animatelayer addAnimation:theAnimation forKey:@"animateOpacity"];

//Add CALayer to View
[self.view.layer insertSublayer:animatelayer atIndex:0];

For details Click here

Monday, 10 October 2016

CABasicAnimation

CABasicAnimation provides basic, single-keyframe animation capabilities for a layer property.
CABasicAnimation class animates a layer property between two values, a starting and an ending value. To move a layer from one point to another in its containing window, for example, we can create a basic animation using the keypath position. We give the animation a start value and an ending value and add the animation to the layer.

Here i am going to create a search animation, animation start with a small circle with minimum radius and continue increase the radius and after maximum radius again its start animate the circle from minimum radius.

First create  a Project(SearchActivityIndicatorViewSample)

Now create a new file(SearchActivityIndicatorView) which is subclass of UIView.
We are going to display a animated circle, so for creating a  circle i am going to declare another Class(SearchActivityIndicatorCircleView) inside "SearchActivityIndicatorView".
SearchActivityIndicatorCircleView class also a subclass of UIView.

Ok, Why i am creating a separate class for display a circle?
Answer is, if we want to display more than one circle as a search indicator so we can use multiple instance of that class and we don't need to write code for multiple circle. So by using this approach     we can avoid duplication of code.
 and also declare a property for stroke color inside "SearchActivityIndicatorCircleView Class".

here the code snippet

@interface SearchActivityIndicatorCircleView : UIView
{
   
}
@property (nonatomic, strong) UIColor *strokeColor;
@end


//Implementation 
@implementation SearchActivityIndicatorCircleView

@end


Add the following methods  inside SearchActivityIndicatorCircleView implementation.
-(instancetype) initWithFrame:(CGRect)frame{
    self = [super initWithFrame: frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}


-(void) drawRect:(CGRect)rect{
    //Drawing Code
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextSetStrokeColorWithColor(context, self.strokeColor.CGColor);
    UIBezierPath *circlePath = [UIBezierPath bezierPath];
    [circlePath addArcWithCenter:CGPointMake(self.bounds.size.width/2, self.frame.size.height/2) radius:MIN(self.frame.size.width, self.frame.size.height)/2 - 5  startAngle:DEGREES_TO_RADIANS(0) endAngle:DEGREES_TO_RADIANS(360) clockwise:YES];
    CGPathRef cgPath = CGPathCreateCopy(circlePath.CGPath);
    CGContextAddPath(context, cgPath);
    CGContextSetLineWidth(context, 1);
    CGContextDrawPath(context, kCGPathStroke);
    CGPathRelease(cgPath);
}


In the first method i override initWithFrame: method for creating a new instance for the class.
and in the second method drawRect: i am creating a circle. Radius of circle is not static, its will depend on the frame size of View.
For calculating the radius i used smallest value between width and height and after getting smallest value reduce 5 from the that, and with the resultant value drawing circle.

Now we have enough code for draw a circle, only need to create a instance of a class and as a sub-view.

Now Switch to SearchActivityIndicatorView.h Class and add following codes.
@interface SearchActivityIndicatorView : UIView
{
    CGFloat maxScale, minScale;
}
@property (nonatomic, assign) BOOL isAnimating;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, assign) NSTimeInterval animationDuration;

-(void) startSearching;
-(void) stopSearching;


Now switch to SearchActivityIndicatorView.m and add following code
-(instancetype) init{
    self = [super init];
    if (self) {
        [self initializeDefaultValues];
    }
    return self;
}
-(instancetype) initWithFrame:(CGRect)frame{
   
    self = [super initWithFrame:frame];
    if (self) {
        [self initializeDefaultValues];
    }
    return self;
}
-(void) awakeFromNib{
    [super awakeFromNib];
    [self initializeDefaultValues];
}
-(void) initializeDefaultValues{
    //set animation suration
    self.animationDuration = 1.9f;
    //set default stroke color
    self.strokeColor = [UIColor redColor];
    //set minimum scale
    minScale = 0.3f;
    //set maximum scale

    maxScale = 8.0f;
}


First 3 methods are used to creating new instance for the class
and the last method set default value with the time of new instance creation of class.
Inside this method, i am defining default value for animation duration, color of circle' stroke, minimum and maximum scale for circle view.

Now its time to add SearchActivityIndicatorCircleView
-(void) addCircleSearchView{
   //1. get minimum value between width and height
    CGFloat width = MIN(self.frame.size.width, self.frame.size.height)/4;

   //2. Create an instance of SearchActivityIndicatorCircleView
    SearchActivityIndicatorCircleView *circleSearchView = [[SearchActivityIndicatorCircleView alloc] initWithFrame:CGRectMake(0, 0, width, width)];
    [circleSearchView setStrokeColor:self.strokeColor];
    circleSearchView.center = self.center;
    //3.Add CABasicAnimation for scale view
    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    //4. set animation duration time
    scaleAnimation.duration = self.animationDuration;
    //5. set repeat count to maximum
    scaleAnimation.repeatCount = CGFLOAT_MAX;
    //6. set minimum value for animation
    scaleAnimation.fromValue = @(minScale);
    //7. set maximum value for animation
    scaleAnimation.toValue = @(maxScale);
    //8. set timing function
    scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];

    //9. add animation to Circle layer
    [circleSearchView.layer addAnimation:scaleAnimation forKey:kSearchScaleAnimationKey];
   //10. add SearchActivityIndicatorCircleView as a subview
    [self addSubview:circleSearchView];
}


Above method create an instance for  SearchActivityIndicatorCircleView, add basic animation for animate a circle and add newly created instances as a subview.
Here step by step explanations:
1. Find minimum value between width and height of frame and divide by 4 means the frame of circle view is 4 times less than SearchActivityIndicatorView.
2. Create an instance of  SearchActivityIndicatorCircleView with the minimum frame size.
3. Create an instance of CABasicAnimation with key "transform.scale".
4. set animation duration, the time require for animation of a circle from minimum scale to maximum scale.
5. set repeat count for animation.
6. set minimum scale or starting scale for animation.
7. set maximum scale for animating the circle.
8. timingFunction: A timing function defining the pacing of the animation.
    CAMediaTimingFunction represents one segment of a function describing a timing curve. The
    function maps an input time normalized to the range [0,1] to an
    output time also in the range [0,1]. E.g. these functions are used
    to define the pacing of an animation over its duration (or over the
   duration of one keyframe). Click here for more detail about CAMediaTimingFunction.

9. add animation to circle layer. CABasicAnimation provide capabilities for animate layer property, so we add animation to layer of circle view.
10. Add circle view as a subview.

We have code for draw a circle, add animation to circle.
So,  now its time to display animation, add below code in SearchActivityIndicatorCircleView.m

-(void) startSearching{
   //check if animation is already started
    if (self.isAnimating) {
        return;
    }

   //set flag value true
    self.isAnimating = YES;

  //add circle
    [self addCircleSearchView];
}


 first we are checking, is animation already started if yes than no need to start animation again.
If no than set the flag value true so we can check animation status later.
and last line send a message to  "addCircleSearchView" method for adding a circle view.




Also write a method for stop animation.
-(void) stopSearching{
    if(!self.isAnimating) {
        return;
    }
    for(UIView *searchView in self.subviews) {
        [UIView animateWithDuration:0.9f animations:^{
            searchView.transform = CGAffineTransformMakeScale(7.0f, 7.0f);
            [searchView setAlpha:0.0f];
        } completion:^(BOOL finished) {
            [searchView.layer removeAllAnimations];
            [searchView removeFromSuperview];
        }];
    }
    self.isAnimating = NO;
}


thats enough.
Now Its time for display our effort to end user.
Switch to ViewController.h class, import SearchActivityIndicatorView

add a property IBOutlet  for SearchActivityIndicatorView
@property (nonatomic, weak) IBOutlet SearchActivityIndicatorView *seachActivityIndicatorView;
and add a IBAction for handle user action.
-(IBAction)handleTapGesture:(UITapGestureRecognizer *)sender;

Now switch to  main.storyboard and drag a UIView from Object library.
Select that view and go to identity inspector and change the class from UIView to SearchActivityIndicatorView
 


Connect IBOutlet to SearchActivityIndicatorView.
Add a Tap Gesture Recognizer  to SearchActivityIndicatorView and connect IBAction method.

Now go to ViewController.m class and method for start animation
-(IBAction)handleTapGesture:(UITapGestureRecognizer *)sender{
   
    if (self.seachActivityIndicatorView.isAnimating == YES) {
        [self.seachActivityIndicatorView stopSearching];
    }
    else{
        [self.seachActivityIndicatorView startSearching];
    }
}


Run the app and tap on the screen, we can see a animated circle on screen.
Click here for complete project.

Friday, 6 May 2016

Drawing On CALayer

Layers are often used to provide the backing store for views but can also be used without a view to display content. Layer is a partner of UIVIew. A UIView does not actually draw itself onto the screen; it draws itself into its layer, and it is the layer that is portrayed on the screen.

For drawing on CALayer first call UIGraphicsPushContext(CGContextRef context) inside drawInContext: method, than write drawing code and at the end use UIGraphicsPopContext();

UIGraphicsPushContext(CGContextRef context)  function save the previous graphics state and make the specified context the current context.
UIGraphicsPopContext() function to balance calls to the UIGraphicsPushContext function.  

First Create a subclass of CALayer.
 Add code inside newly created subclass.

-(void) drawInContext:(CGContextRef)ctx{
   
       UIGraphicsPushContext(ctx);
     
     // Drawing code
    UIBezierPath *rectanglePath = [UIBezierPath bezierPath];
    
    //set color for stroke
    [[UIColor blackColor] setStroke];
    
    //Set move point(origin/top left corner)
    [rectanglePath moveToPoint:CGPointMake(0, 0)];
    
    //set top right corner
    [rectanglePath addLineToPoint:CGPointMake(self.frame.size.width, 0)];
    
    //set bottom right corner
    [rectanglePath addLineToPoint:CGPointMake(self.frame.size.width, self.frame.size.height)];
   
    //set bottom left point
    [rectanglePath addLineToPoint:CGPointMake(0,    self.frame.size.height)];
    [rectanglePath closePath];
    rectanglePath.lineWidth = 2;
    [rectanglePath stroke];
    [super drawInContext:ctx];
    UIGraphicsPopContext();
}