Is it possible to draw the following in objective-c? I tried using the image, but It pixelates. So I figured it is best to draw it programatically. Can someone provide me some sample code to achieve this.
Thank you.
Use a CAShapeLayerand assign it a path describing your shape:
- (UIBezierPath *)createBubblePathInFrame:(CGRect) frame{
CGFloat arrowInset = 10;
CGFloat arrowHeight = 10;
CGFloat arrowWidth = 20;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, arrowHeight)];
[path addLineToPoint:CGPointMake(arrowInset, arrowHeight)];
[path addLineToPoint:CGPointMake(arrowInset+arrowWidth/2, 0)];
[path addLineToPoint:CGPointMake(arrowInset+arrowWidth, arrowHeight)];
[path addLineToPoint:CGPointMake(frame.size.width, arrowHeight)];
[path addLineToPoint:CGPointMake(frame.size.width, frame.size.height)];
[path addLineToPoint:CGPointMake(0, frame.size.height)];
[path addLineToPoint:CGPointMake(0, arrowHeight)];
return path;
}
Use it like this:
CAShapeLayer *shapelayer = [CAShapeLayer layer];
shapelayer.frame = CGRectMake(50, 50, 200, 100);
shapelayer.path = [self createBubblePathInFrame:shapelayer.bounds].CGPath;
shapelayer.fillColor = [UIColor grayColor].CGColor;
shapelayer.strokeColor = [UIColor redColor].CGColor;
shapelayer.lineWidth = 1;
[self.view.layer addSublayer:shapelayer];
Or you can draw it yourself in drawRect:
[[UIColor grayColor] setFill];
[bezierPath fill];
[[UIColor redColor] setStroke];
[bezierPath stroke];
You can use this as a triangle view:
#implementation Triangle
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColor clearColor];
self.alpha = 0.75;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMinY(rect)); // top left
CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMinY(rect)); // top right
CGContextAddLineToPoint(ctx, CGRectGetMidX(rect), CGRectGetMaxY(rect)); // bottom mid
CGContextClosePath(ctx);
CGContextSetRGBFillColor(ctx, 25.0/255.0, 25.0/255.0, 25.0/255.0, 1.0);
CGContextFillPath(ctx);
}
#end
Then just subclass a UIView and add an instance of Triangle where appropriate (in your case on the top left corner).
For your purpose you also should rotate this triangle 180 degrees as the code above drwas a triangle that points downwards.
Related
I need help to draw trapezoid shapes in iOS.
I am using the following code to draw the Pink shape, but it is not working:
UIBezierPath* trianglePath = [UIBezierPath bezierPath];
[trianglePath moveToPoint:CGPointMake(0, 0)];
[trianglePath addLineToPoint:CGPointMake(topView.frame.size.width, topView.frame.size.height/2)];
[trianglePath addLineToPoint:CGPointMake(100, topView.frame.size.height/2)];
CAShapeLayer *triangleMaskLayer = [CAShapeLayer layer];
[triangleMaskLayer setPath:trianglePath.CGPath];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,topView.frame.size.height-150, 200, 150)];
view.layer.mask = triangleMaskLayer;
[self.view addSubview:view];
How can I draw the pink-colored shape?
-(void)TriangularPinkView{
UIBezierPath *path = [UIBezierPath bezierPath];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.lineWidth = 0.5;
CGPoint start = CGPointMake(CGRectGetMinX(self.pinkView.frame), CGRectGetMidY(self.pinkView.frame)+CGRectGetHeight(self.pinkView.frame)*.25);
[path moveToPoint:start];
[path addLineToPoint:CGPointMake(CGRectGetMaxX(self.pinkView.frame), CGRectGetMidY(self.pinkView.frame))];
[path addLineToPoint:CGPointMake(CGRectGetMaxX(self.pinkView.frame), CGRectGetMaxY(self.pinkView.frame))];
[path addLineToPoint:CGPointMake(CGRectGetMinX(self.pinkView.frame), CGRectGetMaxY(self.pinkView.frame))];
shapeLayer.path = [path CGPath];
// shapeLayer.fillRule = kCAFillRuleEvenOdd;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
}
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];
The code below is drawing me a circle, how can I modify the existing code to draw a triangle instead?
_colorDotLayer = [CALayer layer];
CGFloat width = self.bounds.size.width-6;
_colorDotLayer.bounds = CGRectMake(0, 0, width, width);
_colorDotLayer.allowsGroupOpacity = YES;
_colorDotLayer.backgroundColor = self.annotationColor.CGColor;
_colorDotLayer.cornerRadius = width/2;
_colorDotLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
While there are shown several Core Graphics solution, I want to add a Core Animation based solution.
- (void)viewDidLoad
{
[super viewDidLoad];
UIBezierPath* trianglePath = [UIBezierPath bezierPath];
[trianglePath moveToPoint:CGPointMake(0, view3.frame.size.height-100)];
[trianglePath addLineToPoint:CGPointMake(view3.frame.size.width/2,100)];
[trianglePath addLineToPoint:CGPointMake(view3.frame.size.width, view2.frame.size.height)];
[trianglePath closePath];
CAShapeLayer *triangleMaskLayer = [CAShapeLayer layer];
[triangleMaskLayer setPath:trianglePath.CGPath];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0, size.width, size.height)];
view.backgroundColor = [UIColor colorWithWhite:.75 alpha:1];
view.layer.mask = triangleMaskLayer;
[self.view addSubview:view];
}
code based on my blog post.
#implementation TriangleView {
CAShapeLayer *_colorDotLayer;
}
- (void)layoutSubviews {
[super layoutSubviews];
if (_colorDotLayer == nil) {
_colorDotLayer = [CAShapeLayer layer];
_colorDotLayer.fillColor = self.annotationColor.CGColor;
[self.layer addSublayer:_colorDotLayer];
}
CGRect bounds = self.bounds;
CGFloat radius = (bounds.size.width - 6) / 2;
CGFloat a = radius * sqrt((CGFloat)3.0) / 2;
CGFloat b = radius / 2;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, -radius)];
[path addLineToPoint:CGPointMake(a, b)];
[path addLineToPoint:CGPointMake(-a, b)];
[path closePath];
[path applyTransform:CGAffineTransformMakeTranslation(CGRectGetMidX(bounds), CGRectGetMidY(bounds))];
_colorDotLayer.path = path.CGPath;
}
- (void)awakeFromNib {
[super awakeFromNib];
self.annotationColor = [UIColor redColor];
}
#end
Result:
I think is more easy than this solutions:
UIBezierPath *path = [UIBezierPath new];
[path moveToPoint:(CGPoint){20, 0}];
[path addLineToPoint:(CGPoint){40, 40}];
[path addLineToPoint:(CGPoint){0, 40}];
[path addLineToPoint:(CGPoint){20, 0}];
// Create a CAShapeLayer with this triangular path
// Same size as the original imageView
CAShapeLayer *mask = [CAShapeLayer new];
mask.frame = self.viewTriangleCallout.bounds;
mask.path = path.CGPath;
This is my white triangle:
You can change points or rotate if you want:
UIBezierPath *path = [UIBezierPath new];
[path moveToPoint:(CGPoint){0, 0}];
[path addLineToPoint:(CGPoint){40, 0}];
[path addLineToPoint:(CGPoint){20, 20}];
[path addLineToPoint:(CGPoint){0, 0}];
// Create a CAShapeLayer with this triangular path
// Same size as the original imageView
CAShapeLayer *mask = [CAShapeLayer new];
mask.frame = self.viewTriangleCallout.bounds;
mask.path = path.CGPath;
Example code, it is based on this SO Answer which draws stars:
#implementation TriangleView
-(void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
int sides = 3;
double size = 100.0;
CGPoint center = CGPointMake(160.0, 100.0);
double radius = size / 2.0;
double theta = 2.0 * M_PI / sides;
CGContextMoveToPoint(context, center.x, center.y-radius);
for (NSUInteger k=1; k<sides; k++) {
float x = radius * sin(k * theta);
float y = radius * cos(k * theta);
CGContextAddLineToPoint(context, center.x+x, center.y-y);
}
CGContextClosePath(context);
CGContextFillPath(context); // Choose for a filled triangle
// CGContextSetLineWidth(context, 2); // Choose for a unfilled triangle
// CGContextStrokePath(context); // Choose for a unfilled triangle
}
#end
Use UIBezeierPaths
CGFloat radius = 20;
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, (center.x + bottomLeft.x) / 2, (center.y + bottomLeft.y) / 2);
CGPathAddArcToPoint(path, NULL, bottomLeft.x, bottomLeft.y, bottomRight.x, bottomRight.y, radius);
CGPathAddArcToPoint(path, NULL, bottomRight.x, bottomRight.y, center.x, center.y, radius);
CGPathAddArcToPoint(path, NULL, center.x, center.y, bottomLeft.x, bottomLeft.y, radius);
CGPathCloseSubpath(path);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithCGPath:path];
CGPathRelease(path);
I'm trying a UIBezierPath for the first time and am trying to fill a graph I've drawn with a color but without success. This is what I've done within a custom UIView:
- (void)calculateGraphSize
{
self.topY = CGRectGetMinY(self.bounds);
self.bottomY = CGRectGetMaxY(self.bounds);
self.minX = CGRectGetMinX(self.bounds);
self.maxX = CGRectGetMaxX(self.bounds);
}
- (void) drawRect: (CGRect) rect
{
CGSize cornerRadius = CGSizeMake(10.0f, 10.0f);
[self calculateGraphSize];
UIBezierPath *graphBorder = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:cornerRadius];
[[UIColor redColor] setFill];
[graphBorder fill];
UIBezierPath *barGraph = [UIBezierPath bezierPath];
barGraph.lineWidth = 2.0f;
CGPoint point = CGPointMake(self.minX, self.bottomY);
[barGraph moveToPoint:point];
point = CGPointMake(self.minX + 50, self.bottomY - 50);
[barGraph addLineToPoint:point];
point = CGPointMake(self.minX + 100, self.bottomY - 75);
[barGraph addLineToPoint:point];
point = CGPointMake(self.minX + 200, self.bottomY);
[barGraph addLineToPoint:point];
[[UIColor blackColor] setStroke];
[[UIColor greenColor] setFill];
[barGraph closePath];
[barGraph stroke];
}
Just add [barGraph fill]:
[[UIColor blackColor] setStroke];
[[UIColor greenColor] setFill];
[barGraph closePath];
[barGraph fill];
[barGraph stroke];
You probably want to fill and then stroke as I can't remember if the fill will cover up the stroke (I always have to check ha!)
I am trying to add inner shadow on few UITextField and UITextView. I have set cornerRadius property for these controls to 1.0. and I am using the code which is mentioned below to create the inner shadow. But problem is that the shadow appears with the steep rectangular corners while the text view and the text field are with rounded corners.
I am calling following method in my viewcontroller class to add the shadow on my text field.
[self addInnerShadow:myTextField.frame];
- (void)addInnerShadow:(CGRect)frame
{
CAShapeLayer* shadowLayer = [CAShapeLayer layer];
[shadowLayer setFrame:frame];
[shadowLayer setShadowColor:[[UIColor blackColor] CGColor]];
[shadowLayer setShadowOffset:CGSizeMake(0.0f, 0.0f)];
[shadowLayer setShadowOpacity:1.0f];
[shadowLayer setShadowRadius:5];
[shadowLayer setFillRule:kCAFillRuleEvenOdd];
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectInset(CGRectMake(0, 0, frame.size.width, frame.size.height),-5, -5));
CGMutablePathRef someInnerPath = CGPathCreateMutable();
CGPathAddRect(someInnerPath, NULL, CGRectInset(CGRectMake(0, 0, frame.size.width, frame.size.height), 0, 0));
CGPathAddPath(path, NULL, someInnerPath);
CGPathCloseSubpath(path);
[shadowLayer setPath:path];
CGPathRelease(path);
CAShapeLayer* maskLayer = [CAShapeLayer layer];
[maskLayer setPath:someInnerPath];
[shadowLayer setMask:maskLayer];
[[self.view layer] addSublayer:shadowLayer];
}
This
CGContextRef context = UIGraphicsGetCurrentContext();
// Shadow
UIColor* shadow4 = [[UIColor blackColor] colorWithAlphaComponent: 0.81];
CGSize shadow4Offset = CGSizeMake(0.1, 2.1);
CGFloat shadow4BlurRadius = 5;
UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(20.5, 26.5, 200, 40) cornerRadius: 4];
[[UIColor whiteColor] setFill];
[rectanglePath fill];
CGRect rectangleBorderRect = CGRectInset([rectanglePath bounds], -shadow4BlurRadius, - shadow4BlurRadius);
rectangleBorderRect = CGRectOffset(rectangleBorderRect, -shadow4Offset.width, - shadow4Offset.height);
rectangleBorderRect = CGRectInset(CGRectUnion(rectangleBorderRect, [rectanglePath bounds]), -1, -1);
UIBezierPath* rectangleNegativePath = [UIBezierPath bezierPathWithRect: rectangleBorderRect];
[rectangleNegativePath appendPath: rectanglePath];
rectangleNegativePath.usesEvenOddFillRule = YES;
CGContextSaveGState(context);
{
CGFloat xOffset = shadow4Offset.width + round(rectangleBorderRect.size.width);
CGFloat yOffset = shadow4Offset.height;
CGContextSetShadowWithColor(context,
CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)),
shadow4BlurRadius,
shadow4.CGColor);
[rectanglePath addClip];
CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(rectangleBorderRect.size.width), 0);
[rectangleNegativePath applyTransform: transform];
[[UIColor grayColor] setFill];
[rectangleNegativePath fill];
}
CGContextRestoreGState(context);
[[UIColor blackColor] setStroke];
rectanglePath.lineWidth = 0.5;
[rectanglePath stroke];
Will produce this. You can manipulate this to get your desired effect.
Create path with UIBezierPath
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:frame
byRoundingCorners:UIRectCornerAllCorners
cornerRadii:CGSizeMake(5.0, 5.0)];
And than use it with Layer.