Change direction in stroke animation - ios

I want to revert the direction of a path drawing. So I changed fromValue and toValue propeties, but now full path is visible at the start of animation and it begins to disappear.
I have the path:
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(213.79, 170.83)];
[bezierPath addCurveToPoint: CGPointMake(131.93, 95) controlPoint1: CGPointMake(212.14, 128.68) controlPoint2: CGPointMake(176.13, 95)];
[bezierPath addCurveToPoint: CGPointMake(50, 173.85) controlPoint1: CGPointMake(86.68, 95) controlPoint2: CGPointMake(50, 130.3)];
[bezierPath addCurveToPoint: CGPointMake(131.93, 252.7) controlPoint1: CGPointMake(50, 217.4) controlPoint2: CGPointMake(86.68, 252.7)];
[bezierPath addCurveToPoint: CGPointMake(157.55, 248.76) controlPoint1: CGPointMake(140.88, 252.7) controlPoint2: CGPointMake(149.49, 251.32)];
[bezierPath addCurveToPoint: CGPointMake(209.69, 281) controlPoint1: CGPointMake(166.59, 267.78) controlPoint2: CGPointMake(186.54, 281)];
[bezierPath addCurveToPoint: CGPointMake(267, 225.85) controlPoint1: CGPointMake(241.34, 281) controlPoint2: CGPointMake(267, 256.31)];
[bezierPath addCurveToPoint: CGPointMake(213.79, 170.83) controlPoint1: CGPointMake(267, 196.71) controlPoint2: CGPointMake(243.53, 172.86)];
[bezierPath closePath];
[color0 setStroke];
bezierPath.lineWidth = 11;
[bezierPath stroke];
And the animation:
UIColor* color = [UIColor colorWithRed: 0.369 green: 0.42 blue: 0.475 alpha: 1];
UIBezierPath *bezierPath = [self bezierPath];
CAShapeLayer *bezier = [[CAShapeLayer alloc] init];
bezier.path = bezierPath.CGPath;
bezier.lineCap = kCALineCapRound;
bezier.strokeColor = color.CGColor;
bezier.fillColor = [UIColor clearColor].CGColor;
bezier.strokeStart = 1.0;
bezier.strokeEnd = 0.0;
bezier.lineWidth = 8.0;
bezier.strokeStart = 0.0;
bezier.strokeEnd = 1.0;
[self.view.layer addSublayer:bezier];
if (animate)
{
CABasicAnimation *animateStrokeEnd = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animateStrokeEnd.duration = appDelegate.myPlayer.audioPlayer.duration;
animateStrokeEnd.fromValue = [NSNumber numberWithFloat:1.0f];
animateStrokeEnd.toValue = [NSNumber numberWithFloat:0.0f];
[bezier addAnimation:animateStrokeEnd forKey:#"strokeEndAnimation"];
}

You were on the right track but you should have animated the strokeStart property instead.
Start with having both strokeStart and strokeEnd as 1.0.
Then animate strokeStart from 1.0 to 0.0. This will give you the effect of the path being stroked from the end to the start.
For example when 25% of the path is stoked you will have strokeStart at 0.75 and strokeEnd at 1.0.

Related

How to draw line on Image Pattern exactly

I have a UIImageView. Inside that I am drawing a line wit user touch event. Problem is that a line can be drawn anywhere in UIImageview, but I like to draw line with image pattern only.
For example, look at this image. I need to draw line on image pattern only.
This is my code:
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
touchPoint = [touch locationInView:self.imgColor];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
[path addLineToPoint:CGPointMake(startingPoint.x,startingPoint.y)];
startingPoint=touchPoint;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
[self.imgColor.layer addSublayer:shapeLayer];
[arrLayer addObject:shapeLayer];
NSLog(#"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y);
}
I hope some one solve my problem.
You can try this way.
Let's say you have a bezierPath called maskPath,in my case it is textPath which is used to mask the imageView.
I am using a simple maskView which draws letter Q on imageView.
Adding the maskPath: (Adds a simple Q shaped mask to the imageView)
-(void)applyMask{
//// Text Drawing
textPath = [UIBezierPath bezierPath];
[textPath moveToPoint: CGPointMake(181, 179.8)];
[textPath addLineToPoint: CGPointMake(166, 197.2)];
[textPath addLineToPoint: CGPointMake(189.7, 216.1)];
[textPath addCurveToPoint: CGPointMake(160, 222.1) controlPoint1: CGPointMake(180.1, 220.1) controlPoint2: CGPointMake(170.2, 222.1)];
[textPath addCurveToPoint: CGPointMake(126.4, 214.45) controlPoint1: CGPointMake(147, 222.1) controlPoint2: CGPointMake(135.8, 219.55)];
[textPath addCurveToPoint: CGPointMake(103.3, 194.2) controlPoint1: CGPointMake(117, 209.35) controlPoint2: CGPointMake(109.3, 202.6)];
[textPath addCurveToPoint: CGPointMake(90.1, 165.85) controlPoint1: CGPointMake(97.3, 185.8) controlPoint2: CGPointMake(92.9, 176.35)];
[textPath addCurveToPoint: CGPointMake(85.9, 133.9) controlPoint1: CGPointMake(87.3, 155.35) controlPoint2: CGPointMake(85.9, 144.7)];
[textPath addCurveToPoint: CGPointMake(90.1, 101.95) controlPoint1: CGPointMake(85.9, 123.1) controlPoint2: CGPointMake(87.3, 112.45)];
[textPath addCurveToPoint: CGPointMake(103.3, 73.6) controlPoint1: CGPointMake(92.9, 91.45) controlPoint2: CGPointMake(97.3, 82)];
[textPath addCurveToPoint: CGPointMake(126.4, 53.35) controlPoint1: CGPointMake(109.3, 65.2) controlPoint2: CGPointMake(117, 58.45)];
[textPath addCurveToPoint: CGPointMake(160, 45.7) controlPoint1: CGPointMake(135.8, 48.25) controlPoint2: CGPointMake(147, 45.7)];
[textPath addCurveToPoint: CGPointMake(193.6, 53.35) controlPoint1: CGPointMake(173, 45.7) controlPoint2: CGPointMake(184.2, 48.25)];
[textPath addCurveToPoint: CGPointMake(216.7, 73.6) controlPoint1: CGPointMake(203, 58.45) controlPoint2: CGPointMake(210.7, 65.2)];
[textPath addCurveToPoint: CGPointMake(229.9, 101.95) controlPoint1: CGPointMake(222.7, 82) controlPoint2: CGPointMake(227.1, 91.45)];
[textPath addCurveToPoint: CGPointMake(234.1, 133.9) controlPoint1: CGPointMake(232.7, 112.45) controlPoint2: CGPointMake(234.1, 123.1)];
[textPath addCurveToPoint: CGPointMake(228.1, 171.85) controlPoint1: CGPointMake(234.1, 147.1) controlPoint2: CGPointMake(232.1, 159.75)];
[textPath addCurveToPoint: CGPointMake(209.5, 202.6) controlPoint1: CGPointMake(224.1, 183.95) controlPoint2: CGPointMake(217.9, 194.2)];
[textPath addLineToPoint: CGPointMake(181, 179.8)];
[textPath closePath];
[textPath moveToPoint: CGPointMake(244, 259.3)];
[textPath addLineToPoint: CGPointMake(258.4, 241.3)];
[textPath addLineToPoint: CGPointMake(230.2, 219.1)];
[textPath addCurveToPoint: CGPointMake(254.5, 180.7) controlPoint1: CGPointMake(241, 208.3) controlPoint2: CGPointMake(249.1, 195.5)];
[textPath addCurveToPoint: CGPointMake(262.6, 133.9) controlPoint1: CGPointMake(259.9, 165.9) controlPoint2: CGPointMake(262.6, 150.3)];
[textPath addCurveToPoint: CGPointMake(256.15, 91.75) controlPoint1: CGPointMake(262.6, 119.3) controlPoint2: CGPointMake(260.45, 105.25)];
[textPath addCurveToPoint: CGPointMake(236.8, 55.9) controlPoint1: CGPointMake(251.85, 78.25) controlPoint2: CGPointMake(245.4, 66.3)];
[textPath addCurveToPoint: CGPointMake(204.7, 31) controlPoint1: CGPointMake(228.2, 45.5) controlPoint2: CGPointMake(217.5, 37.2)];
[textPath addCurveToPoint: CGPointMake(160, 21.7) controlPoint1: CGPointMake(191.9, 24.8) controlPoint2: CGPointMake(177, 21.7)];
[textPath addCurveToPoint: CGPointMake(115.3, 31) controlPoint1: CGPointMake(143, 21.7) controlPoint2: CGPointMake(128.1, 24.8)];
[textPath addCurveToPoint: CGPointMake(83.2, 55.9) controlPoint1: CGPointMake(102.5, 37.2) controlPoint2: CGPointMake(91.8, 45.5)];
[textPath addCurveToPoint: CGPointMake(63.85, 91.75) controlPoint1: CGPointMake(74.6, 66.3) controlPoint2: CGPointMake(68.15, 78.25)];
[textPath addCurveToPoint: CGPointMake(57.4, 133.9) controlPoint1: CGPointMake(59.55, 105.25) controlPoint2: CGPointMake(57.4, 119.3)];
[textPath addCurveToPoint: CGPointMake(63.85, 176.05) controlPoint1: CGPointMake(57.4, 148.5) controlPoint2: CGPointMake(59.55, 162.55)];
[textPath addCurveToPoint: CGPointMake(83.2, 211.9) controlPoint1: CGPointMake(68.15, 189.55) controlPoint2: CGPointMake(74.6, 201.5)];
[textPath addCurveToPoint: CGPointMake(115.3, 236.65) controlPoint1: CGPointMake(91.8, 222.3) controlPoint2: CGPointMake(102.5, 230.55)];
[textPath addCurveToPoint: CGPointMake(160, 245.8) controlPoint1: CGPointMake(128.1, 242.75) controlPoint2: CGPointMake(143, 245.8)];
[textPath addCurveToPoint: CGPointMake(211.3, 233.2) controlPoint1: CGPointMake(179.8, 245.8) controlPoint2: CGPointMake(196.9, 241.6)];
[textPath addLineToPoint: CGPointMake(244, 259.3)];
[textPath closePath];
[UIColor.blackColor setFill];
[textPath fill];
maskLayer = [CAShapeLayer layer];
maskLayer.path = [textPath CGPath];
maskLayer.strokeColor = [[UIColor blackColor] CGColor];
maskLayer.lineWidth = 3.0;
maskLayer.fillColor = [[UIColor redColor] CGColor];
[self.imgView.layer addSublayer:maskLayer];
}
You already have the method:
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.imgView];
if ([textPath containsPoint:touchPoint]) {
path=nil; //this is not need,unless u want to start a new path everytime this condition executes.
path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
[path addLineToPoint: CGPointMake(_startingPoint.x,_startingPoint.y)];
_startingPoint=touchPoint;
drawLayer = [CAShapeLayer layer];
drawLayer.path = [path CGPath];
drawLayer.strokeColor = [[UIColor blackColor] CGColor];
drawLayer.lineWidth = 3.0;
drawLayer.fillColor = [[UIColor redColor] CGColor];
[self.imgView.layer addSublayer:drawLayer];
NSLog(#"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y);
}
}
You can now verify , if the touch point is in the textPath whcih is a bezierPath.
If the touchPoint is in the textPath, then allow the draw, else dont draw.
The result will be something like this:
As you see, this code will allow you to draw only in the masked path.
If you want to draw outside of the textPath, then you can do simply:
if (![textPath containsPoint:touchPoint]) {
path=nil; //this is not need,unless u want to start a new path everytime this condition executes.
path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
[path addLineToPoint:CGPointMake(_startingPoint.x,_startingPoint.y)];
_startingPoint=touchPoint;
drawLayer = [CAShapeLayer layer];
drawLayer.path = [path CGPath];
drawLayer.strokeColor = [[UIColor blackColor] CGColor];
drawLayer.lineWidth = 3.0;
drawLayer.fillColor = [[UIColor redColor] CGColor];
[self.imgView.layer addSublayer:drawLayer];
NSLog(#"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y);
}
Note: You need to take care of your touches moved method in drawing the line. As the bezier path method addLineToPoint will add line to the touchPoint and this line may cross the maskedPath. You need to make sure you are close the previosu bezier path and start a new one to avoid the lines to be drawn on the outside part of masked area.
I assume you are you trying to display alphabets in some language, may be you can use that language font for dynamic display. Just a thought. Together with the logic mentioned above you can try this.

Overlapping loader circle

I was trying to reproduce the overlapping circle Apple made for the application "Activity". (See image below).
If you use standard Bezier Path the staring/ending position will have effects only between 0 and 2PI. If you try, for example, to fill for 4PI (even using some shadows) you cannot simulate an overlapping loading.
How is possible to make something similar to the Apple solution to create an overlapping circle?
This shows the general idea--transform is definitely the way to go. You'll have to adjust the sizes, arrows, and shadows for what you need. But the view allow the tint and angle to be adjusted from Interface Builder. This should get you going.
#import <UIKit/UIKit.h>
IB_DESIGNABLE
#interface ActivityCircleView : UIView
#property (nonatomic) IBInspectable CGFloat angleOfRotationInDegrees;
#end
#import "ActivityCircleView.h"
#implementation ActivityCircleView
- (void)setAngleOfRotation:(CGFloat)angleOfRotationInDegrees {
_angleOfRotationInDegrees = angleOfRotationInDegrees;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[self drawActivityWithTintColor:self.tintColor angleOfRotationInDegrees:self.angleOfRotationInDegrees];
}
- (void)drawActivityWithTintColor: (UIColor*)tintColor angleOfRotationInDegrees: (CGFloat)angleOfRotationInDegrees
{
//// General Declarations
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
//// Color Declarations
CGFloat tintColorRGBA[4];
[tintColor getRed: &tintColorRGBA[0] green: &tintColorRGBA[1] blue: &tintColorRGBA[2] alpha: &tintColorRGBA[3]];
UIColor* brighter = [UIColor colorWithRed: (tintColorRGBA[0] * 0.5 + 0.5) green: (tintColorRGBA[1] * 0.5 + 0.5) blue: (tintColorRGBA[2] * 0.5 + 0.5) alpha: (tintColorRGBA[3] * 0.5 + 0.5)];
//// Gradient Declarations
CGFloat gradientLocations[] = {0, 0.73};
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)#[(id)tintColor.CGColor, (id)brighter.CGColor], gradientLocations);
//// Shadow Declarations
NSShadow* shadow = [[NSShadow alloc] init];
[shadow setShadowColor: UIColor.blackColor];
[shadow setShadowOffset: CGSizeMake(0.1, 0.1)];
[shadow setShadowBlurRadius: 5];
//// Activity Circle
{
//// Circle With Overlapping Shadow
{
CGContextSaveGState(context);
CGContextTranslateCTM(context, 50, 50);
CGContextRotateCTM(context, -angleOfRotationInDegrees * M_PI / 180);
//// Left Half Circle Drawing
UIBezierPath* leftHalfCirclePath = UIBezierPath.bezierPath;
[leftHalfCirclePath moveToPoint: CGPointMake(0, -40)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(0, -20) controlPoint1: CGPointMake(0, -40) controlPoint2: CGPointMake(0, -31.68)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(-7.44, -18.57) controlPoint1: CGPointMake(-2.63, -20) controlPoint2: CGPointMake(-5.14, -19.49)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(-20, -0) controlPoint1: CGPointMake(-14.8, -15.62) controlPoint2: CGPointMake(-20, -8.42)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(0, 20) controlPoint1: CGPointMake(-20, 11.05) controlPoint2: CGPointMake(-11.05, 20)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(0, 40) controlPoint1: CGPointMake(0, 27.41) controlPoint2: CGPointMake(0, 34.35)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(-40, -0) controlPoint1: CGPointMake(-22.09, 40) controlPoint2: CGPointMake(-40, 22.09)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(-24.08, -31.94) controlPoint1: CGPointMake(-40, -13.05) controlPoint2: CGPointMake(-33.75, -24.64)];
[leftHalfCirclePath addLineToPoint: CGPointMake(-23.84, -32.13)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(0, -40) controlPoint1: CGPointMake(-17.18, -37.07) controlPoint2: CGPointMake(-8.93, -40)];
[leftHalfCirclePath addLineToPoint: CGPointMake(0, -40)];
[leftHalfCirclePath closePath];
[tintColor setFill];
[leftHalfCirclePath fill];
//// Circle With Shadow Drawing
UIBezierPath* circleWithShadowPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(-10, 20, 20, 20)];
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, shadow.shadowOffset, shadow.shadowBlurRadius, [shadow.shadowColor CGColor]);
[brighter setFill];
[circleWithShadowPath fill];
CGContextRestoreGState(context);
//// Right Half Circle Drawing
UIBezierPath* rightHalfCirclePath = UIBezierPath.bezierPath;
[rightHalfCirclePath moveToPoint: CGPointMake(40, -0)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(0, 40) controlPoint1: CGPointMake(40, 22.09) controlPoint2: CGPointMake(22.09, 40)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(0, 20) controlPoint1: CGPointMake(0, 33.83) controlPoint2: CGPointMake(0, 27.02)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(20, -0) controlPoint1: CGPointMake(11.05, 20) controlPoint2: CGPointMake(20, 11.05)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(0, -20) controlPoint1: CGPointMake(20, -11.05) controlPoint2: CGPointMake(11.05, -20)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(0, -40) controlPoint1: CGPointMake(0, -28.3) controlPoint2: CGPointMake(0, -35.35)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(40, -0) controlPoint1: CGPointMake(22.09, -40) controlPoint2: CGPointMake(40, -22.09)];
[rightHalfCirclePath closePath];
CGContextSaveGState(context);
[rightHalfCirclePath addClip];
CGContextDrawLinearGradient(context, gradient, CGPointMake(20, -40), CGPointMake(20, 40), 0);
CGContextRestoreGState(context);
CGContextRestoreGState(context);
}
//// Arrow
{
//// Arrow Line Drawing
UIBezierPath* arrowLinePath = UIBezierPath.bezierPath;
[arrowLinePath moveToPoint: CGPointMake(43.5, 20.5)];
[arrowLinePath addLineToPoint: CGPointMake(57.5, 20.5)];
arrowLinePath.lineCapStyle = kCGLineCapRound;
[UIColor.blackColor setStroke];
arrowLinePath.lineWidth = 4;
[arrowLinePath stroke];
//// Arrow Head Drawing
UIBezierPath* arrowHeadPath = UIBezierPath.bezierPath;
[arrowHeadPath moveToPoint: CGPointMake(50.8, 14.5)];
[arrowHeadPath addLineToPoint: CGPointMake(57.5, 20.5)];
[arrowHeadPath addLineToPoint: CGPointMake(50.8, 26.5)];
arrowHeadPath.lineCapStyle = kCGLineCapRound;
[UIColor.blackColor setStroke];
arrowHeadPath.lineWidth = 4;
[arrowHeadPath stroke];
}
}
//// Cleanup
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
#end
By the way, I cheated a bit and used PaintCode.
Here's my attempt:
It's generated entirely in code (I had to use the Angle Gradient Layer to get the gradient, but the rest of the code is mine). I can easily obtain any desired angle just by applying a rotation transform:
Of course I also hard-coded all the values, because I was just trying it out, but feel free to play with it:
let con = UIGraphicsGetCurrentContext()
let c1 = UIColor(red: 0.8, green: 0.8, blue: 0.7, alpha: 1).CGColor
let c2 = UIColor(red: 0.8, green: 0.8, blue: 0.1, alpha: 1).CGColor
let outer:CGFloat = 20
let diff:CGFloat = 20
let inner:CGFloat = outer + diff
func circle(inset:CGFloat) {
CGContextAddEllipseInRect(con, rect.rectByInsetting(
dx: inset, dy: inset))
}
CGContextSaveGState(con)
circle(outer); circle(inner); CGContextEOClip(con)
let im = AngleGradientLayer.newImageGradientInRect(
rect, colors:[c1,c2], locations:[0,1]).takeRetainedValue()
CGContextDrawImage(con, rect, im)
CGContextRestoreGState(con)
circle(outer)
CGContextStrokePath(con)
circle(inner)
CGContextStrokePath(con)
let (_,lower) = rect.rectsByDividing(rect.height / 2, fromEdge: .MinYEdge)
CGContextAddRect(con, lower)
CGContextEOClip(con)
CGContextSetFillColorWithColor(con, c1)
CGContextSaveGState(con)
CGContextSetShadowWithColor(con, CGSizeMake(0,3), 6,
UIColor.blackColor().colorWithAlphaComponent(0.7).CGColor)
let top = lower.origin.y - diff/2
let left = rect.width - diff * 2
circle(outer); circle(inner); CGContextEOClip(con)
CGContextFillEllipseInRect(con, CGRectMake(left,top,diff,diff))
CGContextRestoreGState(con)
CGContextStrokeEllipseInRect(con, CGRectMake(left,top,diff,diff))

Does the way CALayer generate its contents Affect its scale animation?

#interface CircleRevealLayer : CALayer
#end
#implementation CircleRevealLayer
- (instancetype)init
{
if (self = [super init]) {
[self setNeedsDisplay];
[self displayIfNeeded];
}
return self;
}
- (void)display
{
self.contents = (__bridge id)([self maskImage].CGImage);
self.contentsGravity = kCAGravityCenter;
}
- (UIImage *)maskImage
{
static UIImage *mask = nil;
if (!mask) {
UIGraphicsBeginImageContext(CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT));
UIBezierPath* bezierPath = UIBezierPath.bezierPath;
[bezierPath moveToPoint: CGPointMake(209.5, 368)];
[bezierPath addCurveToPoint: CGPointMake(207, 370.5) controlPoint1: CGPointMake(208.12, 368) controlPoint2: CGPointMake(207, 369.12)];
[bezierPath addCurveToPoint: CGPointMake(209.5, 373) controlPoint1: CGPointMake(207, 371.88) controlPoint2: CGPointMake(208.12, 373)];
[bezierPath addCurveToPoint: CGPointMake(212, 370.5) controlPoint1: CGPointMake(210.88, 373) controlPoint2: CGPointMake(212, 371.88)];
[bezierPath addCurveToPoint: CGPointMake(210.98, 368.49) controlPoint1: CGPointMake(212, 369.67) controlPoint2: CGPointMake(211.6, 368.94)];
[bezierPath addCurveToPoint: CGPointMake(209.5, 368) controlPoint1: CGPointMake(210.57, 368.18) controlPoint2: CGPointMake(210.05, 368)];
[bezierPath closePath];
[bezierPath moveToPoint: CGPointMake(411, 0)];
[bezierPath addCurveToPoint: CGPointMake(411, 736) controlPoint1: CGPointMake(411, 0) controlPoint2: CGPointMake(411, 736)];
[bezierPath addLineToPoint: CGPointMake(-3, 736)];
[bezierPath addLineToPoint: CGPointMake(-3, 0)];
[bezierPath addLineToPoint: CGPointMake(411, 0)];
[bezierPath addLineToPoint: CGPointMake(411, 0)];
[bezierPath closePath];
[UIColor.grayColor setFill];
[bezierPath fill];
mask = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//mask = [UIImage imageNamed:#"mask.PNG"];
}
return mask;
}
#end
#interface CircleRevealView : UIView
#end
#implementation CircleRevealView
+ (Class)layerClass{
return [CircleRevealLayer class];
}
#end
then, I create it like this:
_maskView = [[CircleRevealView alloc] initWithFrame:self.view.bounds];
_maskView.frame = self.view.bounds;
and add a scale animation:
POPSpringAnimation *springAnimation = [POPSpringAnimation animation];
springAnimation.property = [POPAnimatableProperty propertyWithName:kPOPViewScaleXY];
springAnimation.toValue=[NSValue valueWithCGPoint:CGPointMake(80, 80)];
springAnimation.velocity=[NSValue valueWithCGPoint:CGPointMake(1, 1)]; // change of value units per second
springAnimation.springBounciness=20; // value between 0-20 default at 4
springAnimation.springSpeed=3;
springAnimation.name=#"scaleXY1";
springAnimation.delegate=self;
[_maskView pop_addAnimation:springAnimation forKey:#"scaleXY1"];
the mask.PNG is just a white image with a hole in the center.
when I use UIBezierPath to draw the contents and assign it to the layer, the scale animation seems to happen from the top-left corner of the layer;
but if I instead use a image , the scale animation seems to happen from the center of it.
what I want is to generate dynamic contents with Core Graphics and scale the layer like when I use mask.PNG
update:
UIBezierPath
mask.PNG
the mask.PNG is generated from the UIBezierPath code, with the PaintCode.

Creating a triangle shape in a UIButton

I am trying to create a button with a triangle icon/shape in it. I have created the triangle in Paintcode then copied the beizer path and added it to the button layer as below.
-(void)setupShowHideRouteButton {
UIBezierPath* bezierPath = UIBezierPath.bezierPath;
[bezierPath moveToPoint: CGPointMake(10.5, 8.5)];
[bezierPath addCurveToPoint: CGPointMake(40.5, 8.5) controlPoint1: CGPointMake(39.5, 8.5) controlPoint2: CGPointMake(40.5, 8.5)];
[bezierPath addLineToPoint: CGPointMake(26.39, 22.3)];
[bezierPath addLineToPoint: CGPointMake(25.2, 23.5)];
[bezierPath addLineToPoint: CGPointMake(10.5, 8.5)];
[UIColor.blackColor setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = self.showHideRouteViewBtn.bounds;
shapeLayer.path = bezierPath.CGPath;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
shapeLayer.strokeColor = [UIColor blackColor].CGColor;
shapeLayer.lineWidth = 2;
[self.showHideRouteViewBtn.layer addSublayer:shapeLayer];
}
However, this does not appear to work. I am setting the background color of the UIButton so I know the frame is correct and outlet working as expected it is just not adding the shape?
Second Approach
UIBezierPath* bezierPath = UIBezierPath.bezierPath;
[bezierPath moveToPoint: CGPointMake(10.5, 8.5)];
[bezierPath addCurveToPoint: CGPointMake(40.5, 8.5) controlPoint1: CGPointMake(39.5, 8.5) controlPoint2: CGPointMake(40.5, 8.5)];
[bezierPath addLineToPoint: CGPointMake(26.39, 22.3)];
[bezierPath addLineToPoint: CGPointMake(25.2, 23.5)];
[bezierPath addLineToPoint: CGPointMake(10.5, 8.5)];
[UIColor.blackColor setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];
// Create a mask layer and the frame to determine what will be visible in the view.
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
CGRect maskRect = self.showHideRouteViewBtn.bounds;
// Create a path with the rectangle in it.
CGPathRef path = CGPathCreateWithRect(maskRect, NULL);
// Set the path to the mask layer.
maskLayer.path = bezierPath.CGPath;
// Release the path since it's not covered by ARC.
CGPathRelease(path);
// Set the mask of the view.
self.showHideRouteViewBtn.layer.mask = maskLayer;
This did not work either.
Try the following:
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = self.showHideRouteViewBtn.bounds;
shapeLayer.path = bezierPath.CGPath;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
shapeLayer.strokeColor = [UIColor blackColor].CGColor;
shapeLayer.lineWidth = 2;
self.showHideRouteViewBtn.layer.mask = shapeLayer;

Masking UIImage in TableViewCell

I have an UITableView where each cell is a picture, name and button, just like the favorites tab in the phone app in iOS 7. And, just like it is in the phone app, I want the image in each cell to be a circle, rather then a square.
Using a program called PaintCode, I have generated a UIBezierPath which I wanted to place over the cell.imageView in order to make the image look like it's a circle. Here is that code
//// Color Declarations
UIColor* fillColor = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 0];
UIColor* fillColor2 = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 1];
//// Bezier Drawing
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(36.36, 26.36)];
[bezierPath addCurveToPoint: CGPointMake(30.5, 40.5) controlPoint1: CGPointMake(32.45, 30.26) controlPoint2: CGPointMake(30.5, 35.38)];
[bezierPath addLineToPoint: CGPointMake(30.5, 20.5)];
[bezierPath addLineToPoint: CGPointMake(50.5, 20.5)];
[bezierPath addCurveToPoint: CGPointMake(36.36, 26.36) controlPoint1: CGPointMake(45.38, 20.5) controlPoint2: CGPointMake(40.26, 22.45)];
[bezierPath closePath];
[bezierPath moveToPoint: CGPointMake(70.5, 60.5)];
[bezierPath addLineToPoint: CGPointMake(50.5, 60.5)];
[bezierPath addCurveToPoint: CGPointMake(64.64, 54.64) controlPoint1: CGPointMake(55.62, 60.5) controlPoint2: CGPointMake(60.74, 58.55)];
[bezierPath addCurveToPoint: CGPointMake(70.5, 40.5) controlPoint1: CGPointMake(68.55, 50.74) controlPoint2: CGPointMake(70.5, 45.62)];
[bezierPath addCurveToPoint: CGPointMake(64.64, 26.36) controlPoint1: CGPointMake(70.5, 35.38) controlPoint2: CGPointMake(68.55, 30.26)];
[bezierPath addCurveToPoint: CGPointMake(50.5, 20.5) controlPoint1: CGPointMake(60.74, 22.45) controlPoint2: CGPointMake(55.62, 20.5)];
[bezierPath addLineToPoint: CGPointMake(70.5, 20.5)];
[bezierPath addLineToPoint: CGPointMake(70.5, 60.5)];
[bezierPath closePath];
[bezierPath moveToPoint: CGPointMake(36.36, 54.64)];
[bezierPath addCurveToPoint: CGPointMake(50.5, 60.5) controlPoint1: CGPointMake(40.26, 58.55) controlPoint2: CGPointMake(45.38, 60.5)];
[bezierPath addLineToPoint: CGPointMake(30.5, 60.5)];
[bezierPath addLineToPoint: CGPointMake(30.5, 40.5)];
[bezierPath addCurveToPoint: CGPointMake(36.36, 54.64) controlPoint1: CGPointMake(30.5, 45.62) controlPoint2: CGPointMake(32.45, 50.74)];
[bezierPath closePath];
[fillColor2 setFill];
[bezierPath fill];
[fillColor setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];
Simply put, I don't know how to use this code to apply this mask to the cell's image view. Any suggestions?
I think you can accomplish this more easily by just editing the cornerRadius property of the UIImageView's layer (after importing QuartzCore), and then setting masksToBounds to true. Check out this answer: How to crop UIImage on oval shape or circle shape?

Resources