How to create a custom Shaped UIView? - objective-c

I want to create a UIView in Star, Pentagon, Hexagon, and Other custom Shapes.
I want to draw inside that custom shapes.
I've created a bezierPath and trying to mask the UIView to it.
but it doesn't work
CGFloat x=48;
CGFloat y=306;
oval2Path = UIBezierPath.bezierPath;
[oval2Path moveToPoint: CGPointMake(x+340, y+427.5)];
[oval2Path addLineToPoint: CGPointMake(x+476.95, y+523.2)];
[oval2Path addLineToPoint: CGPointMake(x+424.64, y+678.05)];
[oval2Path addLineToPoint: CGPointMake(x+255.36, y+678.05)];
[oval2Path addLineToPoint: CGPointMake(x+203.05, y+523.2)]; [oval2Path closePath];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = oval2Path.CGPath;
FinalAlgView *myView=[[FinalAlgView alloc]initWithFrame:CGRectMake(0,0,800,800)];
myView.backgroundColor=[UIColor whiteColor];
myView.layer.mask = mask;
[self.view bringSubviewToFront:drawShape];
[self.view addSubview:myView];
IS there anyway to create UIView as custom Shapes

Related

Create UIView with four corner points?

How can i create UIView with four corner.
0 = "NSPoint: {79.583483072916664, 54.148963562011716}"; // top left
1 = "NSPoint: {274.96375, 30.877176879882814}"; // top right
2 = "NSPoint: {306.15565104166666, 357.91370518493653}"; // bottom right
3 = "NSPoint: {77.101464843749994, 363.47374218750002}"; // bottom left
I have no idea where to start.
As your view is not a regular rectangle you need to first draw a path i.e. BezierPath and get a shape and imposing the shape on to the View. This view myView would behave like any other normal view
UIView *myView = [[UIView alloc]initWithFrame:self.view.frame];
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:CGPointMake(points[0].x, points[0].y)];
[linePath addLineToPoint:CGPointMake(points[1].x, points[1].y)];
[linePath addLineToPoint:CGPointMake(points[2].x, points[2].y)];
[linePath addLineToPoint:CGPointMake(points[3].x, points[3].y)];
[linePath closePath];
CAShapeLayer *shape = [[CAShapeLayer alloc]init];
[shape setPath:linePath.CGPath];
myView.layer.mask=shape;
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
The output ScreenShot is as given below:
Your 4 corner points do not make a rectangle - a UIView cannot be an arbitrary quadrilateral.
For drawing irregular shapes you should look at Apple's docs for using bezier paths: https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/BezierPaths/BezierPaths.html
So something like this:
- (void)drawRect:(CGRect)rect {
[[UIColor redColor] setStroke];
[[UIColor yellowColor] setFill];
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:CGPointMake(points[0].x, points[0].y)];
[linePath addLineToPoint:CGPointMake(points[1].x, points[1].y)];
[linePath addLineToPoint:CGPointMake(points[2].x, points[2].y)];
[linePath addLineToPoint:CGPointMake(points[3].x, points[3].y)];
[linePath setLineWidth:LINE_WIDTH];
[linePath closePath];
}
What you want is polygon shape and not rectangle. You can not assign polygon shape to view. but if you want to display only part of view fall between these points, you can draw UIBezierPath path with these points on view and then apply blend to clip outer part. here is sample code.
self.backgroundColor = [UIColor redColor];
UIBezierPath *aPath = [UIBezierPath bezierPath];
[aPath moveToPoint:CGPointMake( a.x, a.y)];
[aPath addLineToPoint:CGPointMake(b.x, b.y)];
[aPath addLineToPoint:CGPointMake(c.x, c.y)];
[aPath addLineToPoint:CGPointMake( d.x, d.y)];
[aPath closePath];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = aPath.CGPath;
[self.layer setMask:shapeLayer];
You can use CALayer for corners, Below lines create a view with corners rounded by 8.
UIView *myView = [[UIView alloc] init];
myView.layer.masksToBounds = YES;
myView.layer.cornerRadius = 8.0;
Or you can create view with certain frame like
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(x, y, w, h)];

How to animate a drawn line in Objective C?

I am trying to animate drawn objects, for example I have drawn a line with this approach:
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(Center.x, Center.y)];
[path addLineToPoint:CGPointMake(Point.x,Point.y)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor whiteColor] CGColor];
shapeLayer.lineWidth = 1.5;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
After a while I need to animate the line to have a different Point, but keeping Center as is, but I have no idea how to do that. Is my approach alright? Is there a better way to do so?
Solved it:
CABasicAnimation *morph = [CABasicAnimation animationWithKeyPath:#"path"];
morph.duration = 1.0;
UIBezierPath *path5 = [UIBezierPath bezierPath];
[path5 moveToPoint:CGPointMake(P22.x+5, P22.y+5)];
[path5 addLineToPoint:CGPointMake(P21.x,P21.y)];
morph.fromValue = (id) path.CGPath;
morph.toValue = (id) path5.CGPath;
[shapeLayer addAnimation:morph forKey:nil];
//next line to update the shapeLayer's new path
shapeLayer.path = path5.CGPath;

Turning a shape made by a bezier path into a SKNode while maintain attributes such as color and gradients

I know with SKShapeNode you can set its shape to a bezier path, however is there a way to transfer the bezier path "as is" with all the colors into a SKNode?
For example, I have this code for a shape:
//// General Declarations
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
//// Color Declarations
UIColor* fillColor = [UIColor colorWithRed: 0.333 green: 0.333 blue: 0.333 alpha: 1];
UIColor* strokeColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 1];
//// Gradient Declarations
NSArray* gradientColors = [NSArray arrayWithObjects:
(id)fillColor.CGColor,
(id)strokeColor.CGColor, nil];
CGFloat gradientLocations[] = {0, 1};
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)gradientColors, gradientLocations);
//// Bezier Drawing
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(-0.5, 51.54)];
[bezierPath addLineToPoint: CGPointMake(209.94, 51.54)];
[bezierPath addLineToPoint: CGPointMake(198.28, 88.97)];
[bezierPath addLineToPoint: CGPointMake(357.67, 90.5)];
[bezierPath addLineToPoint: CGPointMake(358.25, 51.54)];
[bezierPath addLineToPoint: CGPointMake(480.5, 56.92)];
[bezierPath addLineToPoint: CGPointMake(480.5, 0.5)];
[bezierPath addLineToPoint: CGPointMake(-0.5, 0.5)];
[bezierPath addLineToPoint: CGPointMake(-0.5, 51.54)];
[bezierPath closePath];
CGContextSaveGState(context);
[bezierPath addClip];
CGContextDrawLinearGradient(context, gradient, CGPointMake(240, 90.5), CGPointMake(240, 0.5), 0);
CGContextRestoreGState(context);
[strokeColor setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];
//// Cleanup
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
This code when drawn on the screen makes a shape that looks like this:
Is there a way I can turn this shape into a SKNode while maintaining the color and gradient? Thank you for your help.
First of SKShapeNode is a subclass of SKNode, so everything you can do with an SKNode you can do with a SKShapeNode.
An SKNode is not "displayable". It's a holder for other nodes which can be rendered like SKShapeNode and SKSpriteNode. If you want a SKSpriteNode from your SKShapeNode you can use SKView's textureFromNode: and thus obtaining a SKTexture which you can use to initialise a SKSpriteNode.

Animating NSView via NSBezierPath

I have some NSBezierPath, and some NSView. I want to animate this NSView and use NEBezierPath as a animation path.
Creating CAKeyframeAnimation with path from UIBezierPath on IOS works fine for me, but for OSX it's not exactly the same.
Here is the code:
self.headView = [[NSView alloc] initWithFrame:NSMakeRect(100, 100, 50, 50)];
[self.headView setWantsLayer:YES];
[self.headView.layer setBackgroundColor:[NSColor redColor].CGColor];
[self.contentView addSubview:self.headView];
NSBezierPath *path = [NSBezierPath bezierPath];
[path moveToPoint:pathStart];
[path curveToPoint:endPoint controlPoint1:[pointValue pointValue] controlPoint2:[pointValue pointValue]];
[path setLineWidth:3.0];
[[NSColor whiteColor] set];
[path stroke];
CAKeyframeAnimation *posAnim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
posAnim.path = [path quartsPath];
posAnim.duration = 1.0;
posAnim.calculationMode = kCAAnimationLinear;
[self.headView.layer addAnimation:posAnim forKey:#"posAnim"];
Converting NSBezierPath to CGPathRef is from there: https://developer.apple.com/library/mac/documentation/cocoa/Conceptual/CocoaDrawingGuide/Paths/Paths.html#//apple_ref/doc/uid/TP40003290-CH206-SW2
But it doesn't animate at all, here is the video: http://d.pr/v/glqQ
I don't getting what is the problem...
P.S. I prefer Keyframe animation because I would like to add some bouncing effect latter.
Make sure the superview of your headView also has a valid layer. Try this:
self.contentView.wantsLayer = YES;

Adding Bezier path to CGPath: ObjectiveC

I have a rectangle drawn using drawRect method.
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect outline = CGRectMake(4, 4, width - 8, height - 8);
CGColorRef white = [[UIColor whiteColor] CGColor];
CGColorRef black = [[UIColor blackColor] CGColor];
CGContextSetFillColorWithColor(context, white);
CGContextFillEllipseInRect(context, outline);
CGContextSetLineWidth(context, 2.0f);
CGContextSetStrokeColorWithColor(context, black);
CGContextStrokeEllipseInRect(context, outline);
I have a bezier path drawn in the samedrawn rect method.
[[UIColor blackColor] setStroke];
[[UIColor whiteColor] setFill];
UIBezierPath * path = [UIBezierPath bezierPath];
[path moveToPoint:point1];
[path addQuadCurveToPoint:point3 controlPoint:point2];
[path addQuadCurveToPoint:point5 controlPoint:point4];
[path setLineWidth:2.0f];
[path stroke];
[path fill];
I need to add a CALayer over these two shapes so that they appear as one.
aPath = CGPathCreateMutable();
CGPathAddEllipseInRect(aPath, nil, outline);
CGPathCloseSubpath(aPath);
pathCopy = CGPathCreateCopyByTransformingPath(aPath, nil);
myLayer = nil;
myLayer = [CAShapeLayer layer];
myLayer.path = pathCopy;
myLayer.fillColor = [[UIColor whiteColor] CGColor];
[self.layer addSublayer:myLayer];
The problem is that I cant add the bezier path to the CGPath. That's one.
Another one is that I cant add a border color or border width to the layer which I am creating. Can anyone help?
Try:
CGPathAddPath(aPath, nil, path.CGPath);
Where aPath is your mutable CGPath and path is your UIBezierPath.