IOS Difference Between uiview and uilabel for drawing - ios

So i have a weird problem when im trying to draw in a custom class that has a subclass of a uiview the lines are thick and fuzzy but when i change the subclass to a uilabel it looks smooth and thin. Just curious are there different default settings enabled for this to occur and if so what are they ?
cant post screens yet
Thanks in advance
Update:
Relevent code note no changes are being made between changing of the subclass
CGContextRef ctx = UIGraphicsGetCurrentContext();
// CGContextSetAllowsAntialiasing(ctx, YES);
// CGContextSetShouldAntialias(ctx,YES);
// CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh);
CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
CGContextSetShadow(ctx, CGSizeMake(0, 3), 2);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, 1, 0);
CGContextAddCurveToPoint(ctx, 5, self.frame.size.height - 10, 15, self.frame.size.height - 1, 30, self.frame.size.height - 1);
CGContextAddLineToPoint(ctx, self.frame.size.width - 30, self.frame.size.height - 1);
CGContextAddCurveToPoint(ctx, self.frame.size.width - 15, self.frame.size.height - 1, self.frame.size.width - 5, self.frame.size.height - 10, self.frame.size.width - 1, 0);
[AppDel.styleChangerController.RoomHightlightColor setFill];
CGContextDrawPath(ctx, kCGPathFillStroke);
[super drawRect: rect];

Related

IOS - Drawing rounded corner square

I am trying to create a 200px square with rounded corners to use as an IOS toast style indication.
I have the following so far -
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1].CGColor);
CGContextMoveToPoint(context, 10, 0);
CGContextAddLineToPoint(context, 95, 0);
CGContextAddArcToPoint(context, 100, 0, 100, 5, 10);
CGContextAddLineToPoint(context, 100, 95);
CGContextAddArcToPoint(context, 100, 100, 95, 100, 10);
CGContextAddLineToPoint(context, 5, 100);
CGContextAddArcToPoint(context, 0, 100, 0, 95, 10);
CGContextAddLineToPoint(context, 0, 5);
CGContextAddArcToPoint(context, 0, 0, 5, 0, 10);
CGContextFillPath(context);
}
I got this far by following a tutorial - it draws a perfect 100px with rounded corners square - but I need a 150px square! I have changed every setting imaginable - with some bizzare results - but cant work out how the width height is defined!? Can anyone advise?
Update for Swift:
The below answer was correct that the time it was written for simple use cases. Things have changed a lot since then so heres an updated answer for swift.
You can create a UIView extension, to add methods to round all corners, or round specific corners. Adding #IBInspectable to the first property means it can be used in interface builder without requiring code
The second function is more complicated and can't be used as an #IBInspectable directly. It will need to be called inside the viewDidLayoutSubviews of the parent to ensure the mask doesn't cut off content as AutoLayout grows / shrinks the content.
extension UIView {
#IBInspectable public var cornerRadius: CGFloat {
set {
layer.cornerRadius = newValue
}
get {
return layer.cornerRadius
}
}
public func roundCorners(corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
Once added to your project you can simply do:
myView.cornerRadius = 4
or
myView.roundCorners(corners: [.topLeft, .topRight], radius: 4)
Very old Objective-c answer:
If you import QuartzCore framework:
#import <QuartzCore/QuartzCore.h>
and add it to your project, you can use the below:
UIView *temp = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
temp.layer.cornerRadius = 5;
If you must draw in drawRect and other stuff will be drawn in future, then just use bezierpath, otherwise see Simon's answer for simple rounded corners on a view
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
[[UIColor blueColor] setFill];
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect /*CGRectMake(0, 0, 150, 150)*/ cornerRadius:10.0];
[path fill];
}
Convert numbers to variables/constants.
Change variables/constants values.
Profit!
Here's your code, modified to show what I mean (untested):
- (void)drawRect:(CGRect)rect {
static CGFloat length = 100;
static CGFloat rounding = 5;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1].CGColor);
CGContextMoveToPoint(context, rounding * 2, 0);
CGContextAddLineToPoint(context, length - rounding, 0);
CGContextAddArcToPoint(context, length, 0, length, rounding, rounding * 2);
CGContextAddLineToPoint(context, length, length - rounding);
CGContextAddArcToPoint(context, length, length, length - rounding, length, rounding * 2);
CGContextAddLineToPoint(context, rounding, length);
CGContextAddArcToPoint(context, 0, length, 0, length - rounding, rounding * 2);
CGContextAddLineToPoint(context, 0, rounding);
CGContextAddArcToPoint(context, 0, 0, rounding, 0, rounding * 2);
CGContextFillPath(context);
}
I also wonder about the 10s in your code. As far as I can see they should be 5s instead. Anyways, the easier solution is to use a UIBezierPath as others have demonstrated (the layer solution does work, but it obviously won't work if you for example want to draw something below the rounded rect and something above it).
Why don't you use a bezier path?
CGFloat radius = 4;
CGRect rect = CGRectMake(0,0,200,200);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
[[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1] setFill];
[path fill];

Drawing concentric circle : Inner circle should be filled

Im trying to achieve a button shapped as
This is the current code I'm trying . It achieves concentric circle but the outer one is filled instead. Help.
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, rect);
CGContextAddEllipseInRect(ctx,
CGRectMake(
rect.origin.x + 10,
rect.origin.y + 10,
rect.size.width - 20,
rect.size.height - 20));
CGContextSetFillColor(ctx, CGColorGetComponents([[UIColor blueColor] CGColor]));
CGContextEOFillPath(ctx);
Make two contexts and fill only the inner circle
- (void)drawRect:(CGRect)rect
{
CGContextRef outer = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(outer, 1.5);
CGContextSetStrokeColorWithColor(outer, [UIColor blueColor].CGColor);
CGContextAddEllipseInRect(outer, CGRectMake(rect.origin.x + 5, rect.origin.y + 5, rect.size.width - 10, rect.size.height - 10));
CGContextStrokePath(outer);
CGContextRef inner = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(inner, 1.5);
CGContextSetFillColorWithColor(inner, [UIColor blueColor].CGColor);
CGContextAddEllipseInRect(inner, CGRectMake(rect.origin.x + 15, rect.origin.y + 15, rect.size.width - 30, rect.size.height - 30));
CGContextFillPath(inner);
}
I have added padding of 5 units to outer context so that it looks like circle and not rounded rectangle.
In your custom view drawRect:
CGContextSetLineWidth(outerCircleContext, 1.0);
CGContextSetStrokeColorWithColor(outerCircleContext, [UIColor greenColor].CGColor);
CGRect outerRectangle = CGRectMake(CGRectGetMidX(rect) - 25, CGRectGetMidY(rect) - 25 , 50, 50);
CGContextAddEllipseInRect(outerCircleContext, outerRectangle);
CGContextStrokePath(outerCircleContext);
CGContextRef innerCircleContext = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(innerCircleContext, 1.0);
CGContextSetFillColorWithColor(innerCircleContext, [UIColor greenColor].CGColor);
CGRect innerRectangle = CGRectMake(CGRectGetMidX(rect) - 20, CGRectGetMidY(rect) - 20 , 40, 40);
CGContextAddEllipseInRect(innerCircleContext, innerRectangle);
CGContextFillPath(innerCircleContext);
Yo can also use path also.

CGContextClip - Fill intersection

I am trying out a simple fill, two intersecting circles with same radius and to fill the intersection alone.Below is what I tried
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1.0);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
// Draw first circle
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextStrokePath(context);
// Draw second circle
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextEOClip(context);
CGContextFillPath(context);
}
My code doesn't even render second circle in context. I have gone through lot of question related to CGContextClip here in forum but most of them uses CGPath in their sample. Only CGpaths can be clipped? Any suggestions or ideas are appreciated.
Thank you
The functions CGContextStrokePath(), CGContextEOClip() and CGContextFillPath()
all clear the current path. Therefore the final CGContextFillPath() has no path to fill.
The following code should now work to draw the intersection of the circles:
// Use first circle as clipping path:
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextClip(context);
// Draw second circle:
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextFillPath(context);
Update: The following code fills and strokes the intersection:
CGContextSaveGState(context);
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextClip(context);
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextDrawPath(context, kCGPathFillStroke);
CGContextRestoreGState(context);
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextClip(context);
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextDrawPath(context, kCGPathStroke);
(Original code which does not work:)
To fill and stroke a path, use CGContextDrawPath():
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1.0);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextDrawPath(context, kCGPathEOFillStroke);
Did you tried this
- (UIImage *)colorImage:(UIImage *)origImage withColor:(UIColor *)color
{
UIGraphicsBeginImageContextWithOptions(origImage.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, (CGRect){ {0,0}, origImage.size} );
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, origImage.size.height);
CGContextConcatCTM(context, flipVertical);
CGContextDrawImage(context, (CGRect){ pt, origImage.size }, [origImage CGImage]);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
and you can also try Flood Fill

Draw lines that end in a brush shape?

Referring to the following image:
. . . . notice how it does not end in a proper point.
I use the following drawing code:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextMoveToPoint(context, self.width - 20, (self.height / 2) - 5);
CGContextAddLineToPoint(context, self.width - 12, self.height / 2);
CGContextStrokePath(context);
CGContextMoveToPoint(context, self.width - 20, (self.height / 2) + 5);
CGContextAddLineToPoint(context, self.width - 12, self.height / 2);
CGContextStrokePath(context);
Is there an easy way to say that a line should end in a point? I know that I could fix this by modifying the coordinates slightly, but I'm curious to learn more.
The lines are not joined, so the CGLineJoin style does not take effect. It should be fine with the following code:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextMoveToPoint(context, self.width - 20, (self.height / 2) - 5);
CGContextAddLineToPoint(context, self.width - 12, self.height / 2);
CGContextAddLineToPoint(context, self.width - 20, self.height / 2 + 5);
CGContextStrokePath(context);

IOS 6 - Custom UIButton how to give my titleLabel a margin?

I'm drawing an inset rectangular border to my UIButton subclass inside the drawRect: method.
As you can see that shape is too close to my button titleLabel frame. How can I set the titleLabel's max width/margin to avoid this?
DrawRect: method
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor bluecolor].CGColor);
CGContextSetLineWidth(context, 2.0);
CGContextMoveToPoint(context, 4,4);
CGContextAddLineToPoint(context, 56, 4);
CGContextAddLineToPoint(context, 56, 56);
CGContextAddLineToPoint(context, 4, 56);
CGContextAddLineToPoint(context, 4,3);
// and now draw the Path!
CGContextStrokePath(context);
}
Use self.titleEdgeInsets=UIEdgeInsetsMake(0, 5, 0, 5); in drawRect method.
Try this code....
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
UIEdgeInsets edgeInsets = button.titleEdgeInsets;
edgeInsets.left -= 5;
edgeInsets.right += 5;
button.titleEdgeInsets = edgeInsets;
From xCode, this can be set using the Inset property as shown in the screenshot below:

Resources