Rectangle 27 141

How to draw a Bzier path in a custom view

It wasn't long ago that I didn't even know how to pronounce Bzier, let alone know how to use Bzier paths to make a custom shape. The following is what I have learned. It turns out that they aren't as scary as they seem at first.

These are the main steps:

  • Design the outline of the shape you want.
  • Divide the outline path into segments of lines, arcs, and curves.
  • Build that path programmatically.
  • Draw the path either in drawRect or using a CAShapeLayer.

You could do anything, but as an example I have chosen the shape below. It could be a popup key on a keyboard.

Look back at your shape design and break it down into simpler elements of lines (for straight lines), arcs (for circles and round corners), and curves (for anything else).

Here is what our example design would look like:

  • Orange dots are the control points for the curves
  • Green dots are the points between path segments
  • Dotted lines show the bounding rectangle
  • Dark blue numbers are the segments in the order that they will be added programmatically

We'll arbitrarily start in the bottom left corner and work clockwise. I'll use the grid in the image to get the x and y values for the points. I'll hardcode everything here, but of course you wouldn't do that in a real project.

The basic process is:

UIBezierPath
  • Choose a starting point on the path with moveToPoint
addLineToPoint
addArcWithCenter
addCurveToPoint
  • Close the path with closePath

Here is the code to make the path in the image above.

func createBezierPath() -> UIBezierPath {

    // create a new path
    let path = UIBezierPath()

    // starting point for the path (bottom left)
    path.move(to: CGPoint(x: 2, y: 26))

    // *********************
    // ***** Left side *****
    // *********************

    // segment 1: line
    path.addLine(to: CGPoint(x: 2, y: 15))

    // segment 2: curve
    path.addCurve(to: CGPoint(x: 0, y: 12), // ending point
        controlPoint1: CGPoint(x: 2, y: 14),
        controlPoint2: CGPoint(x: 0, y: 14))

    // segment 3: line
    path.addLine(to: CGPoint(x: 0, y: 2))

    // *********************
    // ****** Top side *****
    // *********************

    // segment 4: arc
    path.addArc(withCenter: CGPoint(x: 2, y: 2), // center point of circle
        radius: 2, // this will make it meet our path line
        startAngle: CGFloat(M_PI), //  radians = 180 degrees = straight left
        endAngle: CGFloat(3*M_PI_2), // 3/2 radians = 270 degrees = straight up
        clockwise: true) // startAngle to endAngle goes in a clockwise direction

    // segment 5: line
    path.addLine(to: CGPoint(x: 8, y: 0))

    // segment 6: arc
    path.addArc(withCenter: CGPoint(x: 8, y: 2),
                          radius: 2,
                          startAngle: CGFloat(3*M_PI_2), // straight up
        endAngle: CGFloat(0), // 0 radians = straight right
        clockwise: true)

    // *********************
    // ***** Right side ****
    // *********************

    // segment 7: line
    path.addLine(to: CGPoint(x: 10, y: 12))

    // segment 8: curve
    path.addCurve(to: CGPoint(x: 8, y: 15), // ending point
        controlPoint1: CGPoint(x: 10, y: 14),
        controlPoint2: CGPoint(x: 8, y: 14))

    // segment 9: line
    path.addLine(to: CGPoint(x: 8, y: 26))

    // *********************
    // **** Bottom side ****
    // *********************

    // segment 10: line
    path.close() // draws the final line to close the path

    return path
}

Note: Some of the above code can be reduced by adding a line and an arc in a single command (since the arc has an implied starting point). See here for more details.

We can draw the path either in a layer or in drawRect.

Method 1: Draw path in a layer

Our custom class looks like this. We add our Bezier path to a new CAShapeLayer when the view is initialized.

import UIKit
class MyCustomView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    func setup() {

        // Create a CAShapeLayer
        let shapeLayer = CAShapeLayer()

        // The Bezier path that we made needs to be converted to 
        // a CGPath before it can be used on a layer.
        shapeLayer.path = createBezierPath().cgPath

        // apply other properties related to the path
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.lineWidth = 1.0
        shapeLayer.position = CGPoint(x: 10, y: 10)

        // add the new layer to our custom view
        self.layer.addSublayer(shapeLayer)
    }

    func createBezierPath() -> UIBezierPath {

        // see previous code for creating the Bezier path
    }
}

And creating our view in the View Controller like this

override func viewDidLoad() {
    super.viewDidLoad()

    // create a new UIView and add it to the view controller
    let myView = MyCustomView()
    myView.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
    myView.backgroundColor = UIColor.yellow
    view.addSubview(myView)

}

Hmm, that's a little small because I hardcoded all the numbers in. I can scale the path size up, though, like this:

let path = createBezierPath()
let scale = CGAffineTransform(scaleX: 2, y: 2)
path.apply(scale)
shapeLayer.path = path.cgPath

Method 2: Draw path in draw

Using draw is slower than drawing to the layer, so this is not the recommended method if you don't need it.

Here is the revised code for our custom view:

import UIKit
class MyCustomView: UIView {

    override func draw(_ rect: CGRect) {

        // create path (see previous code)
        let path = createBezierPath()

        // fill
        let fillColor = UIColor.white
        fillColor.setFill()

        // stroke
        path.lineWidth = 1.0
        let strokeColor = UIColor.blue
        strokeColor.setStroke()

        // Move the path to a new location
        path.apply(CGAffineTransform(translationX: 10, y: 10))

        // fill and stroke the path (always do these last)
        path.fill()
        path.stroke()

    }

    func createBezierPath() -> UIBezierPath {

        // see previous code for creating the Bezier path
    }
}

which gives us the same result...

  • Thinking like a Bzier path (Everything I've ever read from this author is good and the inspiration for my example above came from here.)
  • Bezier Curves (how they are used in graphics applications)
  • Bezier Curves (good description of how the mathematical formulas are derived)

What if frame of the view changes? How can we resize the shape when an orientation change occurs?

@ozgur, There are at least two options. One would be to do a scale (and possibly translate) transform as I showed in my example above. Another option would be to recalculate the Bezier path based on the new frame. In the example above I hard coded all of the numbers into the Bezier path. However, when I have used Bezier paths in actual projects, I determine the Bezier values based on the frame size. When the frame (or more likely, bounds) changes I recalculate the Bezier path.

I chose the latter before. I recalculated the bezier path and updated the layer in question in layoutSubviews method but I am not sure if that is the right place to do it. Where would you update the path when the view's frame has changed?

@ozgur, layoutSubviews definitely sounds like the right place to do it. I would say if that is working then keep it there. Here is an example of where I used a Bezier path. (Scroll to the bottom.) For some reason I didn't put it in layoutSubviews but I don't remember why now. I should probably submit this to code review. I'm no expert. I just made the answer above to learn how to do Bezier paths myself.

@BohdanSavych, the draw method already belongs to the view, so you don't need to add it. It is a standard method defined by UIView for the purpose of drawing. We are just overriding it here so that we can do our own drawing on the view.

ios - Drawing UIBezierPath on code generated UIView - Stack Overflow

ios iphone objective-c uiview uibezierpath
Rectangle 27 141

How to draw a Bzier path in a custom view

It wasn't long ago that I didn't even know how to pronounce Bzier, let alone know how to use Bzier paths to make a custom shape. The following is what I have learned. It turns out that they aren't as scary as they seem at first.

These are the main steps:

  • Design the outline of the shape you want.
  • Divide the outline path into segments of lines, arcs, and curves.
  • Build that path programmatically.
  • Draw the path either in drawRect or using a CAShapeLayer.

You could do anything, but as an example I have chosen the shape below. It could be a popup key on a keyboard.

Look back at your shape design and break it down into simpler elements of lines (for straight lines), arcs (for circles and round corners), and curves (for anything else).

Here is what our example design would look like:

  • Orange dots are the control points for the curves
  • Green dots are the points between path segments
  • Dotted lines show the bounding rectangle
  • Dark blue numbers are the segments in the order that they will be added programmatically

We'll arbitrarily start in the bottom left corner and work clockwise. I'll use the grid in the image to get the x and y values for the points. I'll hardcode everything here, but of course you wouldn't do that in a real project.

The basic process is:

UIBezierPath
  • Choose a starting point on the path with moveToPoint
addLineToPoint
addArcWithCenter
addCurveToPoint
  • Close the path with closePath

Here is the code to make the path in the image above.

func createBezierPath() -> UIBezierPath {

    // create a new path
    let path = UIBezierPath()

    // starting point for the path (bottom left)
    path.move(to: CGPoint(x: 2, y: 26))

    // *********************
    // ***** Left side *****
    // *********************

    // segment 1: line
    path.addLine(to: CGPoint(x: 2, y: 15))

    // segment 2: curve
    path.addCurve(to: CGPoint(x: 0, y: 12), // ending point
        controlPoint1: CGPoint(x: 2, y: 14),
        controlPoint2: CGPoint(x: 0, y: 14))

    // segment 3: line
    path.addLine(to: CGPoint(x: 0, y: 2))

    // *********************
    // ****** Top side *****
    // *********************

    // segment 4: arc
    path.addArc(withCenter: CGPoint(x: 2, y: 2), // center point of circle
        radius: 2, // this will make it meet our path line
        startAngle: CGFloat(M_PI), //  radians = 180 degrees = straight left
        endAngle: CGFloat(3*M_PI_2), // 3/2 radians = 270 degrees = straight up
        clockwise: true) // startAngle to endAngle goes in a clockwise direction

    // segment 5: line
    path.addLine(to: CGPoint(x: 8, y: 0))

    // segment 6: arc
    path.addArc(withCenter: CGPoint(x: 8, y: 2),
                          radius: 2,
                          startAngle: CGFloat(3*M_PI_2), // straight up
        endAngle: CGFloat(0), // 0 radians = straight right
        clockwise: true)

    // *********************
    // ***** Right side ****
    // *********************

    // segment 7: line
    path.addLine(to: CGPoint(x: 10, y: 12))

    // segment 8: curve
    path.addCurve(to: CGPoint(x: 8, y: 15), // ending point
        controlPoint1: CGPoint(x: 10, y: 14),
        controlPoint2: CGPoint(x: 8, y: 14))

    // segment 9: line
    path.addLine(to: CGPoint(x: 8, y: 26))

    // *********************
    // **** Bottom side ****
    // *********************

    // segment 10: line
    path.close() // draws the final line to close the path

    return path
}

Note: Some of the above code can be reduced by adding a line and an arc in a single command (since the arc has an implied starting point). See here for more details.

We can draw the path either in a layer or in drawRect.

Method 1: Draw path in a layer

Our custom class looks like this. We add our Bezier path to a new CAShapeLayer when the view is initialized.

import UIKit
class MyCustomView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    func setup() {

        // Create a CAShapeLayer
        let shapeLayer = CAShapeLayer()

        // The Bezier path that we made needs to be converted to 
        // a CGPath before it can be used on a layer.
        shapeLayer.path = createBezierPath().cgPath

        // apply other properties related to the path
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.lineWidth = 1.0
        shapeLayer.position = CGPoint(x: 10, y: 10)

        // add the new layer to our custom view
        self.layer.addSublayer(shapeLayer)
    }

    func createBezierPath() -> UIBezierPath {

        // see previous code for creating the Bezier path
    }
}

And creating our view in the View Controller like this

override func viewDidLoad() {
    super.viewDidLoad()

    // create a new UIView and add it to the view controller
    let myView = MyCustomView()
    myView.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
    myView.backgroundColor = UIColor.yellow
    view.addSubview(myView)

}

Hmm, that's a little small because I hardcoded all the numbers in. I can scale the path size up, though, like this:

let path = createBezierPath()
let scale = CGAffineTransform(scaleX: 2, y: 2)
path.apply(scale)
shapeLayer.path = path.cgPath

Method 2: Draw path in draw

Using draw is slower than drawing to the layer, so this is not the recommended method if you don't need it.

Here is the revised code for our custom view:

import UIKit
class MyCustomView: UIView {

    override func draw(_ rect: CGRect) {

        // create path (see previous code)
        let path = createBezierPath()

        // fill
        let fillColor = UIColor.white
        fillColor.setFill()

        // stroke
        path.lineWidth = 1.0
        let strokeColor = UIColor.blue
        strokeColor.setStroke()

        // Move the path to a new location
        path.apply(CGAffineTransform(translationX: 10, y: 10))

        // fill and stroke the path (always do these last)
        path.fill()
        path.stroke()

    }

    func createBezierPath() -> UIBezierPath {

        // see previous code for creating the Bezier path
    }
}

which gives us the same result...

  • Thinking like a Bzier path (Everything I've ever read from this author is good and the inspiration for my example above came from here.)
  • Bezier Curves (how they are used in graphics applications)
  • Bezier Curves (good description of how the mathematical formulas are derived)

What if frame of the view changes? How can we resize the shape when an orientation change occurs?

@ozgur, There are at least two options. One would be to do a scale (and possibly translate) transform as I showed in my example above. Another option would be to recalculate the Bezier path based on the new frame. In the example above I hard coded all of the numbers into the Bezier path. However, when I have used Bezier paths in actual projects, I determine the Bezier values based on the frame size. When the frame (or more likely, bounds) changes I recalculate the Bezier path.

I chose the latter before. I recalculated the bezier path and updated the layer in question in layoutSubviews method but I am not sure if that is the right place to do it. Where would you update the path when the view's frame has changed?

@ozgur, layoutSubviews definitely sounds like the right place to do it. I would say if that is working then keep it there. Here is an example of where I used a Bezier path. (Scroll to the bottom.) For some reason I didn't put it in layoutSubviews but I don't remember why now. I should probably submit this to code review. I'm no expert. I just made the answer above to learn how to do Bezier paths myself.

@BohdanSavych, the draw method already belongs to the view, so you don't need to add it. It is a standard method defined by UIView for the purpose of drawing. We are just overriding it here so that we can do our own drawing on the view.

ios - Drawing UIBezierPath on code generated UIView - Stack Overflow

ios iphone objective-c uiview uibezierpath
Rectangle 27 1

You could assign your path to a CAShapeLayer (such as wrapping it in a UIView subclass that returns CAShapeLayer as its +layerClass). The path is assigned to the CGPath -path property (and note that UIBezierPath provides a CGPath property). Then you have a line in a view that you can animate (such as a group animation using UIView +beginAnimations .

so create a CAShapeLayer that is a smallest rectangle that encloses the 2 centers of the circles? And then resize the layer, and consider the direction of slanting (0,0) to (200,200) vs (200,0) to (200,0) as well? Or just create a CAShapeLayer that covers up the whole screen, and draw path any way we want, but if there are 32 or 64 such lines, the memory use might be heavy?

ios - Is content drawn by drawRect able to animate using UIView animat...

ios cocoa-touch uiview uiviewanimation
Rectangle 27 40

You can set the border with this pattern using Layer and Bizer path like below examples.

CAShapeLayer *yourViewBorder = [CAShapeLayer layer];
yourViewBorder.strokeColor = [UIColor blackColor].CGColor;
yourViewBorder.fillColor = nil;
yourViewBorder.lineDashPattern = @[@2, @2];
yourViewBorder.frame = yourView.bounds;
yourViewBorder.path = [UIBezierPath bezierPathWithRect:yourView.bounds].CGPath;
[yourView.layer addSublayer:yourViewBorder];
var yourViewBorder = CAShapeLayer()
yourViewBorder.strokeColor = UIColor.black.cgColor
yourViewBorder.lineDashPattern = [2, 2]
yourViewBorder.frame = yourView.bounds
yourViewBorder.fillColor = nil
yourViewBorder.path = UIBezierPath(rect: yourView.bounds).cgPath
yourView.layer.addSublayer(yourViewBorder)

You can also set different types of design using pattern image like below example.

[yourView.layer setBorderWidth:5.0];
[yourView.layer setBorderColor:[[UIColor colorWithPatternImage:[UIImage imageNamed:@"DotedImage.png"]] CGColor]];///just add image name and create image with dashed or doted drawing and add here

Here you've to add <QuartzCore/QuartzCore> framework in the project and import it with below line in YourViewController.m file.

#import <QuartzCore/QuartzCore.h>

it's not a perfect way when talking about iPhone6 plus. The dotted line could become fuzzy.

@Jacky: use a higher resolution image. :)

what's an example of the image?

can you give a example of the image?

Jonguo For example, if you add any image with proper resolution like suppose your normal image size is 120x120 and it's name is test.png then create another two image with name test@2x.png and test@3x.png with size of 240x240 and 360x360 which is used in all the apple device automatically with it's related name. (i.e. test.png is use in iPhone 4, test@2x will useful for iPhone 4s, 5, 5s, 6, 6s and twst@3x will useful for iPhone 6 plus, 6s plus.

ios - Dashed line border around UIView - Stack Overflow

ios objective-c iphone uiview
Rectangle 27 0

roundedCornerLayer.lineWidth = borderWidth; sets the width of the path. I'm not sure if you want the same path to have different widths or different paths with different widths. If you want different widths in one path then you must break it into separate subpaths and each will have a different lineWidth. If you want to have different paths then just change the value of width when you call the method. Did I miss anything?

Hey thanks for getting back to me. I would like to be able to do this with different line widths on each of the four sides if possible.How do subpaths work?

Since you're not actually drawing the paths but adding them as sublayers, I would say just create a different path for each side and add them to the layer.

But it's a mask so It's clipping the view. Any code sample?

ios - UIBezierPath Path w/ multiple line widths - Stack Overflow

ios core-graphics uibezierpath
Rectangle 27 0

Resources:

The UIBezierPath class lets you define a path consisting of straight and curved line segments and render that path in your custom views. You use this class initially to specify just the geometry for your path. Paths can define simple shapes such as rectangles, ovals, and arcs or they can define complex polygons that incorporate a mixture of straight and curved line segments. After defining the shape, you can use additional methods of this class to render the path in the current drawing context.

'uibezierpath' tag wiki - Stack Overflow

uibezierpath
Rectangle 27 0

//Define the drawing path
UIBezierPath *path1 = [[UIBezierPath alloc] init];
//path Move to start drawing position
[path1 moveToPoint:CGPointMake(200, 100)];
//Draw a straight line from the starting position to100, 200
[path1 addLineToPoint:CGPointMake(100, 100)];
//To draw a line from (100, 200) to (200, 200)
[path1 addLineToPoint:CGPointMake(100, 200)];
//close path
[path1 closePath];

CAShapeLayer *layer1 = [[CAShapeLayer alloc] init];
layer1.path = path1.CGPath;
layer1.fillColor = [UIColor colorWithRed:0.88 green:0.87 blue:0.87 alpha:1.0].CGColor;
[self.view.layer addSublayer:layer1];

UIBezierPath *path2 = [[UIBezierPath alloc] init];
[path2 moveToPoint:CGPointMake(200, 100)];
[path2 addLineToPoint:CGPointMake(200, 200)];
[path2 addLineToPoint:CGPointMake(100, 200)];
[path2 closePath];

CAShapeLayer *layer2 = [[CAShapeLayer alloc] init];
layer2.path = path2.CGPath;
layer2.fillColor = [UIColor colorWithRed:0.89 green:0.57 blue:0.53 alpha:1.0].CGColor;
[self.view.layer addSublayer:layer2];

Here is the result: result image

xcode - Divide Square UIView into Cross Sections iOS Objective C - Sta...

ios xcode uiview square divide
Rectangle 27 0

Is this what you want? This will draw a line diagonally and connect it to its origin in a way that bottom section is made into a path.

func initialSetup() {
    self.view.backgroundColor = UIColor.cyan
    let path = UIBezierPath()
    path.move(to: CGPoint(x: 0, y: self.view.center.y + 40))
    path.addLine(to: CGPoint(x: self.view.frame.size.width, y: self.view.center.y - 40))
    path.addLine(to: CGPoint(x: self.view.frame.size.width, y: self.view.frame.size.height))
    path.addLine(to: CGPoint(x: 0, y: self.view.frame.size.height))
    path.close()

    self.view.drawPolygon(path: path.cgPath)
}

func drawPolygon(path: CGPath) {
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path
    shapeLayer.lineWidth = 2.0
    shapeLayer.strokeColor = UIColor.white.cgColor
    shapeLayer.fillColor = UIColor.white.cgColor
    self.layer.addSublayer(shapeLayer)
}

ios - Bezier path duplicate design - Stack Overflow

ios swift uibezierpath bezier
Rectangle 27 0

let path = UIBezierPath()

let p1 = CGPointMake(0,self.view.frame.height/2)
let p3 = CGPointMake(self.view.frame.width,self.view.frame.height/2)

path.moveToPoint(p1)
path.addQuadCurveToPoint(p3, controlPoint: CGPoint(x: self.view.frame.width/2, y: 0))

let line = CAShapeLayer()
line.path = path.CGPath;
line.strokeColor = UIColor.blackColor().CGColor
line.fillColor = UIColor.redColor().CGColor
view.layer.addSublayer(line)

cocoa touch - Showing UIBezierPath on view - Stack Overflow

cocoa-touch uikit uiview
Rectangle 27 0

How do you build your path? Is it just an accumulation of straight line segments? If so you could keep a list of those (parallel to your UIBezierPath, that you use for rendering), and then perform line intersection tests. It'll be O(N^2), though, in the naive implementation.

can i get some code for this line intersection test and this o(N^2)

objective c - How to detect if an UIBezierPath intersects itself? - St...

objective-c ios intersection uibezierpath cgpath
Rectangle 27 0

(void)animateViewWith3DCurrentView:(UIView *)currentView withPoing:(CGPoint)movePoint
{
    //flip the view by 180 degrees in its place first.
    currentView.layer.transform =          CATransform3DRotate(currentView.layer.transform,myRotationAngle(180), 0, 1, 0);

    //set the anchor point so that the view rotates on one of its sides.
    currentView.layer.anchorPoint = CGPointMake(0.5, 0.5);

    //Set up scaling

    CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:kResizeKey];

    //we are going to fill the screen here. So 423,337
    [resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(423, 337)]];
    resizeAnimation.fillMode            = kCAFillModeForwards;
    resizeAnimation.removedOnCompletion = NO;

     // Set up path movement

    UIBezierPath *movePath = [UIBezierPath bezierPath];

    //the control point is now set to centre of the filled screen. Change this to make the path different.
    // CGPoint ctlPoint       = CGPointMake(0.0, 0.5);
    CGPoint ctlPoint       = CGPointMake(1024/2, 768/2);

    //This is the starting point of the animation. This should ideally be a function of the frame of the view to be animated. Hardcoded here.

    // Set here to get the accurate point..
    [movePath moveToPoint:movePoint];

    //The anchor point is going to end up here at the end of the animation.
    [movePath addQuadCurveToPoint:CGPointMake(1024/2, 768/2) controlPoint:ctlPoint];

    CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:kPathMovement];

    moveAnim.path                = movePath.CGPath;
    moveAnim.removedOnCompletion = YES;

     // Setup rotation animation

    CABasicAnimation* rotateAnimation = [CABasicAnimation animationWithKeyPath:kRotation];
    //start from 180 degrees (done in 1st line)
    CATransform3D fromTransform       = CATransform3DMakeRotation(myRotationAngle(180), 0, 1, 0);
    //come back to 0 degrees
    CATransform3D toTransform         = CATransform3DMakeRotation(myRotationAngle(0), 0, 1, 0);

    //This is done to get some perspective.
    CATransform3D persp1 = CATransform3DIdentity;
    persp1.m34 = 1.0 / -3000;

    fromTransform = CATransform3DConcat(fromTransform, persp1);
    toTransform = CATransform3DConcat(toTransform,persp1);

    rotateAnimation.toValue             = [NSValue valueWithCATransform3D:toTransform];
    rotateAnimation.fromValue           = [NSValue valueWithCATransform3D:fromTransform];
    //rotateAnimation.duration            = 2;
    rotateAnimation.fillMode            = kCAFillModeForwards;
    rotateAnimation.removedOnCompletion = NO;


     // Setup and add all animations to the group

    CAAnimationGroup *group = [CAAnimationGroup animation]; 

    [group setAnimations:[NSArray arrayWithObjects:moveAnim,rotateAnimation, resizeAnimation, nil]];

    group.fillMode            = kCAFillModeForwards;
    group.removedOnCompletion = NO;
    group.duration            = 0.7f;
    group.delegate            = self;

    [group setValue:currentView forKey:kGroupAnimation];

    [currentView.layer addAnimation:group forKey:kLayerAnimation];   
}

iphone - How do I animate CATransform3Ds with a CAKeyframeAnimation? -...

iphone objective-c ios core-animation
Rectangle 27 0

var circleLayer: CAShapeLayer!

override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = UIColor.clear

    // Use UIBezierPath as an easy way to create the CGPath for the layer.
    // The path should be the entire circle.
    let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: (frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(M_PI * 2.0), clockwise: true)

    // Setup the CAShapeLayer with the path, colors, and line width
    circleLayer = CAShapeLayer()
    circleLayer.path = circlePath.cgPath
    circleLayer.fillColor = UIColor.clear.cgColor
    circleLayer.strokeColor = UIColor.red.cgColor
    circleLayer.lineWidth = 5.0;

    // Don't draw the circle initially
    circleLayer.strokeEnd = 0.0

    // Add the circleLayer to the view's layer's sublayers
    layer.addSublayer(circleLayer)
} 

required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
}

func animateCircle(duration: TimeInterval) {
    // We want to animate the strokeEnd property of the circleLayer
    let animation = CABasicAnimation(keyPath: "strokeEnd")

    // Set the animation duration appropriately
    animation.duration = duration

    // Animate from 0 (no circle) to 1 (full circle)
    animation.fromValue = 0
    animation.toValue = 1

    // Do a linear animation (i.e The speed of the animation stays the same)
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)

    // Set the circleLayer's strokeEnd property to 1.0 now so that it's the
    // Right value when the animation ends
    circleLayer.strokeEnd = 1.0

    // Do the actual animation
    circleLayer.add(animation, forKey: "animateCircle")
}
func addCircleView() {
    let diceRoll = CGFloat(Int(arc4random_uniform(7))*50)
    var circleWidth = CGFloat(200)
    var circleHeight = circleWidth

    // Create a new CircleView
    let circleView = CircleView(frame: CGRect(x: diceRoll, y: 0, width: circleWidth, height: circleHeight))
    //let test = CircleView(frame: CGRect(x: diceRoll, y: 0, width: circleWidth, height: circleHeight))

    view.addSubview(circleView)

    // Animate the drawing of the circle over the course of 1 second
    circleView.animateCircle(duration: 1.0)
}
M_PI
CGFloat.pi

swift - Animate drawing of a circle - Stack Overflow

swift circle uiviewanimation progress drawrect
Rectangle 27 0

// Define start & end point for line
            let startPoint = CGPoint.zero
            let endPoint = CGPoint.zero

            // Create line with SKShapeNode
            let line = SKShapeNode()
            let path = UIBezierPath()
            path.move(to: startPoint)
            path.addLine(to: endPoint)
            line.path = path.cgPath
            line.strokeColor = UIColor.white
            line.lineWidth = 2

ios7 - How to draw a line in Sprite-kit - Stack Overflow

ios7 sprite-kit
Rectangle 27 0

//Define the drawing path
UIBezierPath *path1 = [[UIBezierPath alloc] init];
//path Move to start drawing position
[path1 moveToPoint:CGPointMake(200, 100)];
//Draw a straight line from the starting position to100, 200
[path1 addLineToPoint:CGPointMake(100, 100)];
//To draw a line from (100, 200) to (200, 200)
[path1 addLineToPoint:CGPointMake(100, 200)];
//close path
[path1 closePath];

CAShapeLayer *layer1 = [[CAShapeLayer alloc] init];
layer1.path = path1.CGPath;
layer1.fillColor = [UIColor colorWithRed:0.88 green:0.87 blue:0.87 alpha:1.0].CGColor;
[self.view.layer addSublayer:layer1];

UIBezierPath *path2 = [[UIBezierPath alloc] init];
[path2 moveToPoint:CGPointMake(200, 100)];
[path2 addLineToPoint:CGPointMake(200, 200)];
[path2 addLineToPoint:CGPointMake(100, 200)];
[path2 closePath];

CAShapeLayer *layer2 = [[CAShapeLayer alloc] init];
layer2.path = path2.CGPath;
layer2.fillColor = [UIColor colorWithRed:0.89 green:0.57 blue:0.53 alpha:1.0].CGColor;
[self.view.layer addSublayer:layer2];

Here is the result: result image

xcode - Divide Square UIView into Cross Sections iOS Objective C - Sta...

ios xcode uiview square divide
Rectangle 27 0

You can't easily animate the fill of a UIBezierPath (or at least without introducing weird artifacts except in nicely controlled situations). But you can animate the strokeEnd of a path of the CAShapeLayer. And if you make the line width of the stroked path really wide (i.e. the radius of the final circle), and set the radius of the path to be half of that of the circle, you get something like what you're looking for.

For ultimate control, when doing complex UIBezierPath animations, you can use CADisplayLink, avoiding artifacts that can sometimes result when using CABasicAnimation of the path:

private var circleLayer = CAShapeLayer()
private weak var displayLink: CADisplayLink?
private var startTime: CFTimeInterval!

private func configureCircleLayer() {
    circleLayer.fillColor = UIColor(hexCode: "EA535D").cgColor
    circleView.layer.addSublayer(circleLayer)
    updatePath(percent: 0)
}

private func startCircleAnimation() {
    startTime = CACurrentMediaTime()
    displayLink = {
        let _displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:)))
        _displayLink.add(to: .current, forMode: .commonModes)
        return _displayLink
    }()
}

@objc func handleDisplayLink(_ displayLink: CADisplayLink) {   // the @objc qualifier needed for Swift 4 @objc inference
    let percent = CGFloat(CACurrentMediaTime() - startTime) / 15.0
    updatePath(percent: min(percent, 1.0))
    if percent > 1.0 {
        displayLink.invalidate()
    }
}

private func updatePath(percent: CGFloat) {
    let w = circleView.bounds.width
    let center = CGPoint(x: w/2, y: w/2)
    let startAngle: CGFloat = -0.25 * 2 * .pi
    let endAngle: CGFloat = startAngle + percent * 2 * .pi
    let path = UIBezierPath()
    path.move(to: center)
    path.addArc(withCenter: center, radius: w/2, startAngle: startAngle, endAngle: endAngle, clockwise: true)
    path.close()

    circleLayer.path = path.cgPath
}
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    configureCircleLayer()
    startCircleAnimation()
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    displayLink?.invalidate()   // to avoid displaylink keeping a reference to dismissed view during animation
}

I was using a Timer before and I'd like to remove it. Since I also display a video at the same time, I want the animation to run smoothly and avoid screen freezing (video freezing, circle animation freezing or anything UI freezing). I felt like a Timer was to "heavy" since it has to update every 0.01 sec (in my case) on the main thread. Is CADisplayLink really different from a Timer? Is it a better solution?

Yes, CADisplayLink is better than Timer (because it's optimally timed at the start of every screen refresh cycle). But it's still likely to be more computationally intensive than CABasicAnimation. But, if you don't mind kludgy approach, since you can't easily animate the fill of a CAShapeLayer, you can animate a strokeEnd of a path (with no fill) with CABasicAnimation. Just make the path of the stroked path to be half of the desired radius, but then set the lineWidth of the stroke to be the desired radius. It's counter-intuitive, but yields the desired effect. See revised answer.

Yes, that's a possibility I was considering. I'll try that and come back to you.

ios - Animate CAShapeLayer with circle UIBezierPath and CABasicAnimati...

ios swift uibezierpath cashapelayer cabasicanimation
Rectangle 27 0

You are always just drawing to an image context the size of your image view - this of course gets blurry, as you do not adapt to a higher resolution when zoomed in. It would be more sensible to instead create a UIBezierPath once and just add a line to it (with addLineToPoint:) in the touchesMoved method, then draw it in a custom drawRect method via [bezierPath stroke]. You could also just add a CAShapeLayer as a subview of the image view and set its path property to the CGPath property of the bezierPath you created earlier.

iphone - CGContextStrokePath not working when zooming and drawing imag...

iphone ios uiimage core-graphics pinch
Rectangle 27 0

You could assign your path to a CAShapeLayer (such as wrapping it in a UIView subclass that returns CAShapeLayer as its +layerClass). The path is assigned to the CGPath -path property (and note that UIBezierPath provides a CGPath property). Then you have a line in a view that you can animate (such as a group animation using UIView +beginAnimations .

so create a CAShapeLayer that is a smallest rectangle that encloses the 2 centers of the circles? And then resize the layer, and consider the direction of slanting (0,0) to (200,200) vs (200,0) to (200,0) as well? Or just create a CAShapeLayer that covers up the whole screen, and draw path any way we want, but if there are 32 or 64 such lines, the memory use might be heavy?

ios - Is content drawn by drawRect able to animate using UIView animat...

ios cocoa-touch uiview uiviewanimation
Rectangle 27 0

Resources:

The UIBezierPath class lets you define a path consisting of straight and curved line segments and render that path in your custom views. You use this class initially to specify just the geometry for your path. Paths can define simple shapes such as rectangles, ovals, and arcs or they can define complex polygons that incorporate a mixture of straight and curved line segments. After defining the shape, you can use additional methods of this class to render the path in the current drawing context.

'uibezierpath' tag wiki - Stack Overflow

uibezierpath
Rectangle 27 0

A UIBezierPath is just a wrapper for a CGPath, which itself is just a set of instructions for drawing (by stroke or fill, or both). That drawing can take place anywhere. In other words, a UIBezierPath is just a tool for drawing; the important thing is the drawing itself. Given a graphics context (which might be a UIView, a UIImage, a CALayer, whatever), you can do as much drawing as you like in succession - say, a line, then a cubic bezier, then a filled line drawing. But how you perform those drawing bits is totally up to you. You shouldn't really care whether you do it with three UIBezierPaths, one UIBezierPath, multiple paths, one path, subpaths, whatever (or even by copying other drawings into this one) - the final effect is all that matters, i.e. the accumulated drawing ultimately done in this graphics context.

Your question is like asking, "Should I draw this circle with my right hand or my left hand, and should I draw it counter-clockwise or clockwise?" It doesn't matter. Once it's done, what will have been drawn is a circle; that is what's important.

ios6 - how can I combine uibezierpath drawings? - Stack Overflow

ios6 uibezierpath cgpath
Rectangle 27 0

// Step 1 : Add QuartzCore.framework in your project
// Step 2 : Create following two files .h and .m
// Step 3 : How to Use

// Import your custom file
#import "myDrawingView.h"

// Create object and add to your viewcontroller
myDrawingView *obj = [[myDrawingView alloc] initWithFrame:self.view.frame];
[obj drawSquaresWithNumber:17 andSize:self.view.frame.size];
[self.view addSubview:obj];

//------------------------------------------------------
// filename : myDrawingView.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface myDrawingView : UIView
{
    int nSquares;
    CGSize mazeSize;
}

- (void)drawSquaresWithNumber:(int)numberOfSquares andSize:(CGSize)screenSize;

@end
//------------------------------------------------------
    // filename : myDrawingView.m
#import "myDrawingView.h"

@implementation myDrawingView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}


// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code

    // Calculate height and width for each sqaure.
    float area = mazeSize.height*mazeSize.width;

    float squareSize = (area/nSquares)/100;
    NSLog(@"row : %f %f",mazeSize.width/squareSize,mazeSize.height/squareSize);

    int row, col;
    row = ceil(mazeSize.width/squareSize);
    col = ceil(mazeSize.height/squareSize);

    float height = mazeSize.height/row;
    float width = mazeSize.width/col;
    NSLog(@"%d %d",row,col);
    NSLog(@"h %f w %f",height,width);
    NSLog(@"square size : %f",squareSize);
    // Create Current Context To Draw
    CGContextRef context = UIGraphicsGetCurrentContext();

    // Draw Line
    CGContextSetLineWidth(context, 0.5f);
    CGContextSetFillColorWithColor(context, [myDrawingView randomColor].CGColor);
    CGContextSetStrokeColorWithColor(context, [myDrawingView randomColor].CGColor);

    int x ,y, cnt;
    x = y = 0;
    cnt = 1;
    // A loop for number of squares

    for(int i=0;i<row;i++)
    {
        for(int j=0;j<col;j++)
        {
            if(cnt<=nSquares)
            {
                CGRect rect = CGRectMake(x, y, width, height);
                // Draws Squares
                UIBezierPath *path = [UIBezierPath bezierPathWithRect:rect];
                // To draw Oval uncomment
//                    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:rect];
                [path fill];
                [path stroke];
            }
            x += width;
            cnt++;
        }
        x = 0;
        y += height;
    }
}

+ (UIColor *) randomColor {

    CGFloat red =  arc4random()%256;
    CGFloat blue = arc4random()%256;
    CGFloat green = arc4random()%256;
    return [UIColor colorWithRed:abs(red)/255.0f green:abs(green)/255.0f blue:abs(blue)/255.0f alpha:1.0];
}

- (void)drawSquaresWithNumber:(int)numberOfSquares andSize:(CGSize)screenSize
{
    nSquares = numberOfSquares;
    mazeSize = screenSize;
    [self setNeedsDisplay];
}

@end

put that in you viewController's viewDidLoad method

This code is working perfectly now, I want this but when I press the button it will create 17 square and the square not taking frame size I want Square create only in frame li CGRectMake(0,0,500,500); , In this tutorial they are scrolling up and not creating in the frame only, how to do this? Any Idea or suggestion would be welcome.

then you need to edit frame of obj to 500*500 and to change number of squares call method with different parameter [obj drawSquaresWithNumber:20 andSize:CGSizeMake(500,500)];

ios - How to make a "squares" and " circles" click on button in iphone...

iphone ios xcode ipad