ios CGContextRef fill color - ios

I want to draw an arc and fill it. The first picture is what it is. I want to get the effect of the second picture
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// 必须清空背景色,不然绘制出来的区域之外有黑色背景
[self setBackgroundColor:[UIColor clearColor]];
[self setUserInteractionEnabled:NO];
}
return self;
}
- (void)drawRect:(CGRect)rect {
float x = rect.origin.x;
float y = rect.origin.y;
float w = rect.size.width;
float h = rect.size.height;
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor *fullColor = [UIColor whiteColor];
CGContextSetFillColorWithColor(context, fullColor.CGColor);
CGContextSetRGBStrokeColor(context,1,1,1,1);
CGContextMoveToPoint(context,0,h - 22);//圆弧的起始点
CGContextAddQuadCurveToPoint(context, w / 2, h, w, h - 22);
CGContextMoveToPoint(context,0,h - 22);//圆弧的起始点
CGContextAddLineToPoint(context, 0, h);
CGContextAddLineToPoint(context, w, h);
CGContextAddLineToPoint(context, w, h - 22);
CGContextStrokePath(context);
CGContextDrawPath(context, kCGPathFillStroke);
}

- (void)drawRect:(CGRect)rect {
float x = rect.origin.x;
float y = rect.origin.y;
float w = rect.size.width;
float h = rect.size.height;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, CGRectMake(0, h - 22, kScreenWidth , 22));
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
// This method
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextMoveToPoint(context,0,h - 22);
CGContextAddQuadCurveToPoint(context, w / 2, h + 14, w, h - 22);
CGContextDrawPath(context, kCGPathFill);
// This method
CGContextSetBlendMode(context, kCGBlendModeNormal);
}
I found a solution.

CGContextStrokePath() clears the current path. This also applies to CGContextDrawPath(), CGContextEOFillPath(), and, CGContextFillPath().
So when the call CGContextDrawPath(context, kCGPathFillStroke); is made, the current path in the context has just been cleared and is an empty path and nothing is drawn.
Removing the line CGContextStrokePath(context); just above should fix your issue.

Related

How to apply a rotation around the origin with affine transform

I want to rotate a rect 45 degrees with affine transform. I know I have to move the context such that the rect is at the origin, apply the rotation and then move back. I want to fully understand how this works so I started with a small test to rotate it around the origin (0,0 in the coordinate system of the parent view), not moving back. This is the view (green rect in this case) after being translated to the origin:
Then I rotate 10 degrees and it looks like this:
I expect it to use the origin as pivot, but this looks like the origin was also translated, so when I apply the rotation it looks the same as if I would have applied it in the old position, only translated to other point. What am I missing?
This is the code...
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor * redColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0];
float x = 150;
float y = 150;
float w = 120;
float h = 40;
CGRect r = CGRectMake(x, y, w, h);
CGContextSetFillColorWithColor(context, redColor.CGColor);
CGContextFillRect(context, r);
CGContextSaveGState(context);
NSLog(NSStringFromCGRect(self.frame));
//move to the origin
CGAffineTransform transform = CGAffineTransformMakeTranslation(-x, -y);
float rad = DEGREES_TO_RADIANS(10); //with 45 it's outside of the view
CGFloat rotation = rad;
//rotate
transform = CGAffineTransformRotate(transform, rotation);
CGContextConcatCTM(context, transform);
r = CGRectMake(x, y, w, h);
CGContextSetFillColorWithColor(context, [UIColor greenColor].CGColor);
CGContextFillRect(context, r);
CGContextRestoreGState(context);
}
I found the problem. The transformations are applied in inverse order, so it will rotate first, and then do the translation.
If I change it like this:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor * redColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0];
float x = 150;
float y = 150;
float w = 120;
float h = 40;
CGRect r = CGRectMake(x, y, w, h);
CGContextSetFillColorWithColor(context, redColor.CGColor);
CGContextFillRect(context, r);
CGContextSaveGState(context);
NSLog(NSStringFromCGRect(self.frame));
CGAffineTransform transform = CGAffineTransformIdentity;
float rad = DEGREES_TO_RADIANS(10);
CGFloat rotation = rad;
//rotate
transform = CGAffineTransformRotate(transform, rotation);
transform = CGAffineTransformTranslate(transform, -x, -y);
CGContextConcatCTM(context, transform);
r = CGRectMake(x, y, w, h);
CGContextSetFillColorWithColor(context, [UIColor greenColor].CGColor);
CGContextFillRect(context, r);
CGContextRestoreGState(context);
}
Then it works:

iOS drawrect ios6 v ios7

I have an app that basically is a ring size app, I have stored all the CGRect frames in an array and then I pass them into a UIView class. So you can navigate through the array changing the size of the circle.
Works fine on all iOS7 devices, however on an iPad 3 running iOS6 the circle is displaying a different size to that of an iPad mini running iOS7.
What would be causing the discrepancy?
My drawrect code is as follows:
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 0);
CGRect circlePoint = arect;
CGContextFillEllipseInRect(ctx, circlePoint);
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = [UIColorFromRGB(0xecc7da) newGradientToColor:UIColorFromRGB(0xcc6699)];
CGColorSpaceRelease(baseSpace), baseSpace = NULL;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextAddEllipseInRect(context, arect);
CGContextClip(context);
CGPoint gradCenter = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
float gradRadius = MIN(arect.size.width , arect.size.height) ;
CGContextDrawRadialGradient (context, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient), gradient = NULL;
CGContextRestoreGState(context);
CGContextAddEllipseInRect(context, arect);
CGContextDrawPath(context, kCGPathStroke);
}
Ok so an update, here is myView.h file :
#import <UIKit/UIKit.h>
#interface myView : UIView{
CGRect arect;
}
- (id)initWithFrame:(CGRect)frame shaperect:(CGRect)shaperect;
#end
And .m file:
#import "myView.h"
#import "UIColor+EasyGradients.h"
#implementation myView
- (id)initWithFrame:(CGRect)frame shaperect:(CGRect)shaperect;
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
arect = shaperect;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 0);
CGRect circlePoint = arect;
CGContextFillEllipseInRect(ctx, circlePoint);
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = [UIColorFromRGB(0xecc7da) newGradientToColor:UIColorFromRGB(0xcc6699)];
CGColorSpaceRelease(baseSpace), baseSpace = NULL;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextAddEllipseInRect(context, arect);
NSLog(#"x = %f | y = %f | w = %f | h = %f", arect.origin.x, arect.origin.y, arect.size.width, arect.size.height);
CGContextClip(context);
CGPoint gradCenter = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
float gradRadius = MIN(arect.size.width , arect.size.height) ;
CGContextDrawRadialGradient (context, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient), gradient = NULL;
CGContextRestoreGState(context);
CGContextAddEllipseInRect(context, arect);
CGContextDrawPath(context, kCGPathStroke);
}
That file gets called and used from my viewcontroller whos .m code is something like this:
myView *myViewx = [[myView alloc] initWithFrame: container shaperect: CGRectFromString([arrayofRects objectForKey:#"0"])];
myViewx.backgroundColor = [UIColor clearColor];
myViewx.tag = 7;
[self.view addSubview:myViewx];

Core Graphics - Shadow not seen

I wrote a simple drawRect with a intention of drawing a circle, drop a shadow and fill it with blue. I have successfully achieved drawing a circle and filling it in blue but my shadow is not in effect. Instead of fill if I stroke my circle, i see the shadow is inside the circle and during fill it is drawn over by fill colour
rect to my drawRect has dimension [[CustomButton alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
#implementation CustomButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef colorRef = [[UIColor blueColor] CGColor];
CGContextSetStrokeColorWithColor(context, colorRef);
CGContextSetFillColorWithColor(context, [[UIColor blueColor] CGColor]);
CGRect buttonRect = CGRectInset(rect, 3, 3);
CGPoint centerPoint = CGPointMake(CGRectGetMidX(buttonRect ), CGRectGetMidY(buttonRect));
CGFloat radius = CGRectGetWidth(buttonRect) / 2;
CGContextSaveGState(context);
CGContextSetShadow(context, CGSizeMake(15.0, 20.0), 1.0);
CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, 0, 2*M_PI, 1);
CGContextClip(context);
CGContextFillRect(context, buttonRect);
CGContextRestoreGState(context);
CGColorRelease(colorRef);
}
#end
Thank you
Try this:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef colorRef = [[UIColor blueColor] CGColor];
CGContextSetStrokeColorWithColor(context, colorRef);
CGContextSetFillColorWithColor(context, [[UIColor blueColor] CGColor]);
CGRect buttonRect = CGRectInset(rect, 3, 3);
CGPoint centerPoint = CGPointMake(CGRectGetMidX(buttonRect ), CGRectGetMidY(buttonRect));
CGFloat radius = CGRectGetWidth(buttonRect) / 2;
CGContextSaveGState(context);
CGContextSetShadow(context, CGSizeMake(2.0, 2.0), 2.0);
CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, 0, 2*M_PI, 1);
//CGContextClip(context);
CGContextFillPath(context);
CGContextRestoreGState(context);
CGColorRelease(colorRef);
}
Your shadow was rectangular and that is why it was not seen under the circle. I changed the call CGContextFillRect to CGContextFillPath, the path which you already create using CGContextAddArc.
Is this what you were going for?
EDIT
You can find a project here: https://bitbucket.org/reydan/so_circleshadow

How to remove corners for round rect bezier path

I am programming first time using Core Graphics, so don't have much idea that how exactly can I solve the problem.
I am drawing rounded rect bezier path along with gradient and stroke as background view for UITableviewCells. Everything has gone fine, except the extra black corners as shown in figure.
I haven't got any idea why they are showing and exactly what they are. Please can anyone help me? Thanks..
Code for creating cell
#import "CustomCellBackground.h"
.
.
.
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
cell.backgroundView = [[CustomCellBackground alloc] init];
cell.selectedBackgroundView = [[CustomCellBackground alloc]init];
}
// Configure the cell.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.backgroundColor = [UIColor clearColor];
return cell;
}
In CustomCellBackground.m
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGPathRef path = [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:10.0] CGPath];
CGContextAddPath(context, path);
CGContextClip(context);
//CGContextSetLineJoin(context, kCGLineJoinRound);
drawLinearGradientWithFourColors(context, self.bounds);
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context,[UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 1.0);
CGContextAddPath(context, path);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
void drawLinearGradientWithFourColors(CGContextRef context, CGRect rect)
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[] = {0.0, 0.2, 0.5, 1.0};
CGFloat colors[16] = {
85/255.0, 85/255.0, 85/255.0, 1.0,
45/255.0, 45/255.0, 45/255.0, 1.0,
22/255.0, 22/255.0, 22/255.0, 1.0,
0, 0, 0, 1.0
};
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, locations, 4);
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
CGContextSaveGState(context);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
When you init your view , setOpaque parameter for layer of the view and view.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setOpaque:NO];
[self.layer setOpaque:NO];
}
return self;
}
I googled it and pasted the code below. For more info refer link:
Use below code:
typedef enum {
CustomCellBackgroundViewPositionTop,
CustomCellBackgroundViewPositionMiddle,
CustomCellBackgroundViewPositionBottom,
CustomCellBackgroundViewPositionSingle
} CustomCellBackgroundViewPosition;
#interface CustomCellBackgroundView : UIView {
UIColor *borderColor;
UIColor *fillColor;
CustomCellBackgroundViewPosition position;
}
#property(nonatomic, retain) UIColor *borderColor, *fillColor;
#property(nonatomic) CustomCellBackgroundViewPosition position;
#end
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(c, [fillColor CGColor]);
CGContextSetStrokeColorWithColor(c, [borderColor CGColor]);
if (position == CustomCellBackgroundViewPositionTop) {
CGContextFillRect(c, CGRectMake(0.0f, rect.size.height - 10.0f, rect.size.width, 10.0f));
CGContextBeginPath(c);
CGContextMoveToPoint(c, 0.0f, rect.size.height - 10.0f);
CGContextAddLineToPoint(c, 0.0f, rect.size.height);
CGContextAddLineToPoint(c, rect.size.width, rect.size.height);
CGContextAddLineToPoint(c, rect.size.width, rect.size.height - 10.0f);
CGContextStrokePath(c);
CGContextClipToRect(c, CGRectMake(0.0f, 0.0f, rect.size.width, rect.size.height - 10.0f));
} else if (position == CustomCellBackgroundViewPositionBottom) {
CGContextFillRect(c, CGRectMake(0.0f, 0.0f, rect.size.width, 10.0f));
CGContextBeginPath(c);
CGContextMoveToPoint(c, 0.0f, 10.0f);
CGContextAddLineToPoint(c, 0.0f, 0.0f);
CGContextStrokePath(c);
CGContextBeginPath(c);
CGContextMoveToPoint(c, rect.size.width, 0.0f);
CGContextAddLineToPoint(c, rect.size.width, 10.0f);
CGContextStrokePath(c);
CGContextClipToRect(c, CGRectMake(0.0f, 10.0f, rect.size.width, rect.size.height));
} else if (position == CustomCellBackgroundViewPositionMiddle) {
CGContextFillRect(c, rect);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 0.0f, 0.0f);
CGContextAddLineToPoint(c, 0.0f, rect.size.height);
CGContextAddLineToPoint(c, rect.size.width, rect.size.height);
CGContextAddLineToPoint(c, rect.size.width, 0.0f);
CGContextStrokePath(c);
return; // no need to bother drawing rounded corners, so we return
}
// At this point the clip rect is set to only draw the appropriate
// corners, so we fill and stroke a rounded rect taking the entire rect
CGContextBeginPath(c);
addRoundedRectToPath(c, rect, 10.0f, 10.0f);
CGContextFillPath(c);
CGContextSetLineWidth(c, 1);
CGContextBeginPath(c);
addRoundedRectToPath(c, rect, 10.0f, 10.0f);
CGContextStrokePath(c);
}
static void addRoundedRectToPath(CGContextRef context, CGRect rect,
float ovalWidth,float ovalHeight)
{
float fw, fh;
if (ovalWidth == 0 || ovalHeight == 0) {// 1
CGContextAddRect(context, rect);
return;
}
CGContextSaveGState(context);// 2
CGContextTranslateCTM (context, CGRectGetMinX(rect),// 3
CGRectGetMinY(rect));
CGContextScaleCTM (context, ovalWidth, ovalHeight);// 4
fw = CGRectGetWidth (rect) / ovalWidth;// 5
fh = CGRectGetHeight (rect) / ovalHeight;// 6
CGContextMoveToPoint(context, fw, fh/2); // 7
CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);// 8
CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);// 9
CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);// 10
CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); // 11
CGContextClosePath(context);// 12
CGContextRestoreGState(context);// 13
}

Striped Lines appear out of nowhere

I am trying to code a routine that would allow me to create a UIImage that is a rectangle filled with stripes on a gradient background.
My code is below and works fine for most of the cases I tried it out. Interestingly, and this is the hook, it doesn't work when I pass it 21 as height and 5 as stripedWidth.
Once I do this, the stripes appear as they should... horizontally.. but vertically they start at like (y=) -40 and end at about (y=) 4 or so. To see this better, each this image showing the effect in question:
Has anyone any idea why this is happening, or even better, what I can do against it?
-(UIImage*) stripedTextureWithStartingColor:(UIColor*) startColor withEndingColor:(UIColor*) endColor withHeight:(NSUInteger) height withStripeWidth:(NSUInteger) stripeWidth withStripeColor:(UIColor*) stripedColor {
CGSize size = CGSizeMake(2 * stripeWidth, height);
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
#try {
CGContextSetAllowsAntialiasing(context, true);
CGContextSetShouldAntialias(context, true);
NSArray* colors = [NSArray arrayWithObjects:(id) startColor.CGColor, (id) endColor.CGColor, nil];
CGFloat locations[2];
locations[0] = 0.0;
locations[1] = 1.0;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations);
CGColorSpaceRelease(colorSpace);
CGContextDrawLinearGradient(context, gradient, CGPointZero, CGPointMake(0, size.height - 1), 0);
CGGradientRelease(gradient);
CGContextFillPath(context);
int lineWidth = (int) stripeWidth;
CGContextSetLineWidth(context, lineWidth / 2);
int lineCount = (float) size.height / (float) lineWidth;
lineCount -= 2;
for (int i=0; i<lineCount; i++) {
CGContextSetStrokeColorWithColor(context, stripedColor.CGColor);
float x1 = -size.height + i * 2 * lineWidth - lineWidth;
float y1 = size.height - 1 + lineWidth;
float x2 = -size.height + i * 2 * lineWidth + size.height - lineWidth;
float y2 = -lineWidth;
CGContextMoveToPoint(context, x1, y1);
CGContextAddLineToPoint(context, x2, y2);
CGContextStrokePath(context);
}
UIColor* lineTopColor = [[UIColor whiteColor] colorWithAlphaComponent:0.9];
UIColor* lineBottomColor = [[UIColor darkGrayColor] colorWithAlphaComponent:0.5];
CGContextSetStrokeColorWithColor(context, lineTopColor.CGColor);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, size.width + 1, 0);
CGContextStrokePath(context);
CGContextSetStrokeColorWithColor(context, lineBottomColor.CGColor);
CGContextMoveToPoint(context, 0, size.height - 1);
CGContextAddLineToPoint(context, size.width + 1, size.height - 1);
CGContextStrokePath(context);
}
#finally {
CGContextRestoreGState(context);
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Found it, my algorithm was slightly incorrect with the starting of the lines

Resources