How to rotate CAShapeLayer object? - ios

What basically i need to implement is custom button that need to switch between plus icon and a check mark with animation. As a first step i am trying to create horizontal line with CAShapeLayer and trying to rotate by some angle. I cannot figure out what is wrong in it.
UIBezierPath *linePath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0,self.frame.size.width, 10)];
//shape layer for the line
CAShapeLayer *line = [CAShapeLayer layer];
line.backgroundColor = [UIColor redColor].CGColor;
line.path = [linePath CGPath];
line.fillColor = [[UIColor greenColor] CGColor];
line.frame = CGRectMake(0, 10, self.frame.size.width,10);
line.anchorPoint = CGPointMake(0.0, 0.5);
line.transform = CATransform3DMakeRotation(30, 0.0, 0.0, 1.0);
[self.layer addSublayer:line];

The transformation use radian, so you should use
line.transform = CATransform3DMakeRotation(30 * M_PI/180, 0.0, 0.0, 1.0);

I used this library to have what i added, http://code4app.net/ios/BZAnimationButton/5477ed87e24741f10bb03ca0

Related

How to create a circular dotted line as a CALayer?

I read this post Draw dotted (not dashed!) line, with IBDesignable in 2017 about drawing a dotted line (rather than a dashed line). However, I am not too familiar with graphics generally and I'm wondering how I can do this with a CALayer (so I don't have to do the whole get current graphics context thing).
I am trying to produce a dotted line that looks like this (the white part, ignore the background):
Here's the code I have working to produce a dotted line:
CAShapeLayer *shapelayer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:startPoint];
[path addLineToPoint:endPoint];
[path setLineCapStyle:kCGLineCapRound];
UIColor *fill = [UIColor whiteColor];
shapelayer.strokeStart = 0.0;
shapelayer.strokeColor = fill.CGColor;
shapelayer.lineWidth = 4.0;
shapelayer.lineJoin = kCALineJoinRound;
shapelayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:4],[NSNumber numberWithInt:6 ], nil];
shapelayer.path = path.CGPath;
return shapelayer;
How can I mirror the code in the SO post I referenced but continue using a CALayer?
I tried modifying the code from that post like so:
UIBezierPath * path = [[UIBezierPath alloc] init];
[path moveToPoint:startPoint];
[path addLineToPoint:endPoint];
[path setLineWidth:8.0];
CGFloat dashes[] = { path.lineWidth, path.lineWidth * 2 };
[path setLineDash:dashes count:2 phase:0];
[path setLineCapStyle:kCGLineCapRound];
[path stroke];
CAShapeLayer *returnLayer = [CAShapeLayer layer];
returnLayer.path = path.CGPath;
return returnLayer;
However, this ends up drawing nothing.
I hope this will help you.
CAShapeLayer *circleLayer = [CAShapeLayer layer];
[circleLayer setPath:[[UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 100, 100)] CGPath]];
circleLayer.lineWidth = 2.0;
[circleLayer setStrokeColor:[[UIColor redColor] CGColor]];
[circleLayer setFillColor:[[UIColor clearColor] CGColor]];
circleLayer.lineJoin = kCALineJoinRound;
circleLayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:2],[NSNumber numberWithInt:3 ], nil];
// self.bgImage is parentView
[[self.bgImage layer] addSublayer:circleLayer];
self.bgImage.layer.borderWidth = 1.0f;
self.bgImage.layer.borderColor = [[UIColor blueColor]CGColor];
I have attached the output of the image
In my case I had to set the lineCapStyle rather than the lineJoinStyle.

Implement drawing gradient arc with CAShapeLayer

Referring to the accepted answer found here I'm trying to implement this and running into an issue with the path of the CAShapeLayerThe code I have is as follows:
-(void)drawGradientArc{
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
CAShapeLayer *circleLayer = [CAShapeLayer new];
circleLayer.lineWidth = 25;
circleLayer.fillColor = [UIColor clearColor].CGColor;
circleLayer.strokeColor = [UIColor redColor].CGColor;
CGFloat radius = 150;
[bezierPath addArcWithCenter:self.view.center radius:radius startAngle:0 endAngle:M_PI clockwise:YES];
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0,0);
gradientLayer.endPoint = CGPointMake(1,0);
NSMutableArray *colors = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
[colors addObject:(id)[[UIColor colorWithHue:(0.1 * i) saturation:1 brightness:.8 alpha:1] CGColor]];
}
gradientLayer.colors = colors;
[gradientLayer setMask:circleLayer];
circleLayer.path = bezierPath.CGPath;
[self.view.layer addSublayer:circleLayer];
}
This will draw the half circle arc correctly but the path for the gradients is not being set correctly and I was unable to piece together how exactly to configure the code to get this to work using a gradient. There is a CGPathCreateCopyByStrokingPath that I think I may also need to call to set the path properly for the gradient but was not quite sure how. Any help on how to structure the code to get this working would be appreciated. I've also included an image of the gradient that I'm trying to reproduce. a CAShapeLayer and CAGradientLayerapproach would be ideal.
Problem 1: Your layers have no frames. Add this:
gradientLayer.frame = self.view.layer.bounds;
circleLayer.frame = gradientLayer.bounds;
Problem 2: You are adding the wrong layer to your view's layer. Where you have:
[self.view.layer addSublayer:circleLayer];
say this instead:
[self.view.layer addSublayer:gradientLayer];
Result:

Drawing an image on a UIView, and making a transparent hole to see the UIView underneath

I have a UIView I'm trying to put together which will be layered above another view. This new view needs to have a fully transparent hole in it. I've attached a screenshot of what it is I'm trying to accomplish (checkerboard pattern is the underlying UIView that will be adding this new UIView as a sublayer, red is a UIImage).
I have the following code that will render the black background with the hole in the center:
- (void)
drawRect:(CGRect)rect
{
CGRect boxRect = CGRectMake(_location.x - (kPointRadius/2), _location.y - (kPointRadius/2), kPointRadius, kPointRadius);
UIBezierPath *path = [UIBezierPath
bezierPathWithRoundedRect:CGRectMake(0, 0, self.layer.frame.size.width, self.layer.frame.size.height)
cornerRadius:0];
UIBezierPath *circlePath = [UIBezierPath
bezierPathWithRoundedRect:boxRect
cornerRadius:kPointRadius];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
CAShapeLayer *fillLayer = [CAShapeLayer layer];
fillLayer.path = path.CGPath;
fillLayer.fillRule = kCAFillRuleEvenOdd;
fillLayer.fillColor = [UIColor blackColor].CGColor;
fillLayer.borderWidth = 5.0;
fillLayer.borderColor = [UIColor redColor].CGColor;
fillLayer.opacity = 0.7;
[self.layer addSublayer:fillLayer];
}
However, when I add an image to that and use [[UIImage imageNamed:#"testimg" drawAtPoint:CGPointMake(x, y)]; to add the image, the image covers the hole.
Can anyone point me in the right direction here? I'm stumped.
EDIT: I'm now able to get it almost there. I can get everything I need EXCEPT the image layered on top of the black, 90% opaque background is also at 90% opacity.
CGRect boxRect = CGRectMake(
_location.x - (kPointRadius/2),
_location.y - (kPointRadius/2),
kPointRadius,
kPointRadius);
UIBezierPath *path = [UIBezierPath
bezierPathWithRoundedRect:CGRectMake(0, 0, self.layer.frame.size.width, self.layer.frame.size.height) cornerRadius:0];
UIBezierPath *circlePath = [UIBezierPath
bezierPathWithRoundedRect:boxRect
cornerRadius:kPointRadius];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
UIImage *image = [UIImage imageNamed:#"testimg"];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(13, 57, 350, 230)];
imageView.image = image;
CGRect r = CGRectMake(self.layer.frame.origin.x, self.layer.frame.origin.y, self.layer.frame.size.width, self.layer.frame.size.height);
UIGraphicsBeginImageContextWithOptions(r.size, NO, 0);
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextAddPath(c, CGPathCreateCopy(path.CGPath));
CGContextEOClip(c);
CGContextFillRect(c, r);
UIImage* maskim = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CALayer* mask = [CALayer layer];
mask.frame = r;
mask.contents = (id)maskim.CGImage;
imageView.layer.mask = mask;
self.layer.mask = mask;
self.layer.backgroundColor = [UIColor blackColor].CGColor;
self.layer.opacity = 0.8;
[self.layer addSublayer:imageView.layer];
EDIT: I'm now able to get it almost there. I can get everything I need EXCEPT the image layered on top of the black, 90% opaque background is also at 90% opacity.
Instead of setting its opacity, you could set the layer's background color to [UIColor colorWithWhite:0.0 alpha:0.9].

How to connect buttons frame?

I have three buttons, all have different direction.
I have to connect them with a red line.
Just like Tic Tec Toc if game over than how to connect them with line:
How do I set line between them??
Or you can use this code..
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];
This is one way of drawing line :
Here you need to subclass UIView and then use CoreGraphics calls in the drawRect method:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextMoveToPoint(context, 25, 25);
CGContextAddLineToPoint(context, 75, 75);
CGContextStrokePath(context);
}
Another way is using UIBezierPath as follows :
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:shapeLayer];

cant add a shape layer into a view's layer

I'm working on CAShapeLayer by creating a layer using CAShapeLayer like following:
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = CGRectMake(150, 50, 200, 200);
shapeLayer.fillColor = [UIColor whiteColor].CGColor;
shapeLayer.strokeColor = [UIColor orangeColor].CGColor;
[self.view.layer addSublayer:shapeLayer];
However, when I execute the codes and I cant see my shapeLayer in the simulator/device.
What I am missing here.
PS : If I am using CALayer *shapeLayer = [CALayer layer]; it works.Confused
add a path to it, like
shapeLayer.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius)
cornerRadius:radius].CGPath;
A shaped layer needs a shape…
I put this in my View Controller and it works fine:
- (void)viewDidLoad
{
[super viewDidLoad];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = CGRectMake(150, 50, 200, 200);
shapeLayer.fillColor = [UIColor whiteColor].CGColor;
shapeLayer.strokeColor = [UIColor orangeColor].CGColor;
NSUInteger radius = 90;
shapeLayer.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius)
cornerRadius:radius].CGPath;
[self.view.layer addSublayer:shapeLayer];
}
If you change the path like
shapeLayer.path = [UIBezierPath bezierPathWithRect:shapeLayer.bounds].CGPath;
it'll result in

Resources