Objective-C drawRect Custom RGB Fill Color - objective-c

I'm trying to fill a circle in Objective-C with a custom RGB color. Here is my drawRect method:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor *color = [UIColor colorWithRed:10.0 green:131.0 blue:254.0 alpha:1.0];
CGContextSetStrokeColorWithColor(context, [color CGColor]);
CGContextSetLineWidth(context, 1.0);
CGContextAddEllipseInRect(context, [ball getRect]);
CGContextStrokePath(context);
}
Whenever I specify anything in place of [color CGColor] like greenColor it works fine, but with the above code nothing gets rendered (an invisible object). I know it is moving around the page because my update method is NSLog'ing a string for every update.
So, I want to fill and get the outer line of the circle to be the specified RGB color above. What am I doing wrong?
Thanks

[UIColor colorWithRed:green:blue:alpha] accept values between 0.0 to 1.0 (Apple Docs Reference) try changing the code like this:
UIColor *color = [UIColor colorWithRed:10.0/255.0 green:131.0/255.0 blue:254.0/255.0 alpha:1.0];

The value for each parameter in this method call:
[UIColor colorWithRed:10.0 green:131.0 blue:254.0 alpha:1.0];
should be between 0.0 and 1.0.

Related

Issue with using RGB colors in IOS

I want to use RGB color to set set background color of UIButton.
I have lots of UIButtons so I decided to make a custom class.But when I try to use colorWithRed I am getting error.
First Code:
[self.layer setBackgroundColor:[UIColor colorWithRed:60/255.0f green:146/255.0f blue:180/255.0f alpha:1.0f]];
Error
Second Code
self.layer.backgroundColor = [UIColor colorWithRed:60/255.0f green:146/255.0f blue:180/255.0f alpha:1.0f];
Error
try to use this code
self.layer.backgroundColor = [UIColor colorWithRed:60/255.0f green:146/255.0f blue:180/255.0f alpha:1.0f].CGColor;
You need to convert UIColor to CGColor which can be done by above code.
Hope this will solve your problem
layer backgroundcolor is of cgcolorref type, so cant use uicolor. we need to use cgcolor or convert uicolor to cgcolor and use it.
example:
[[UIColor whiteColor] CGColor];
or
[UIColor whiteColor].CGColor;

Core Graphics clipping not working

I have this code to color an area between an inside and outside boundary.
CGContextSaveGState(context);
CGContextAddRect(context, self.bounds);
CGContextAddPath(context, inlinePath);
CGContextEOClip(context);
CGContextAddPath(context, outlinePath);
CGContextClip(context);
CGContextSetFillColorWithColor(context, _myColor.CGColor);
CGContextFillRect(context, self.bounds);
CGContextRestoreGState(context);
This is part of a local routine drawChartInContext:.
It works great when I generate an image like this:
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 2.0);
[self drawChartInContext:UIGraphicsGetCurrentContext()];
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
But when I call it from drawRect I just get the whole outlinePath area filled with _myColor.
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawChartInContext:context];
}
What could be wrong?
Just figured it out. It was a combination of two oversights:
inlinePath had zero area (a special case that is valid)
myColor had 1.0 alpha (a configuration mistake).

NSImage +imageWithPatternColor: and NSGradient - Cocoa/Mac

I am drawing on a custom view an NSGradient like this:
- (void)drawRect: (NSRect)dirtyRect
{
NSGradient* g = [[NSGradient alloc] initWithStartingColor: _color endingColor: [NSColor clearColor]];
[g drawInRect: [self bounds] angle: 90];
}
If _color is a normal color, for example [NSColor blueColor], everything is fine. The problem is that _color comes from a pattern image (which in this case is mostly grey with some fancy pixels on it), and when that happens the program keeps logging this error:
*** -[NSGradient initWithColors:atLocations:colorSpace:]: the color NSPatternColorSpace CGImageSource=0x400367d60"
)> cannot be converted into color space Generic RGB colorspace
_color = [NSColor colorWithPatternImage: [NSImage imageNamed: #"mainBG.png"]]
The image is completely opaque and is a png file.
Any ideas? perhaps I should change the file type? I don't know...
EDIT:
If I define _color like this:
_color = [[NSColor colorWithPatternImage: [NSImage imageNamed: #"mainBG.tiff"]] colorUsingColorSpace: [NSColorSpace genericRGBColorSpace]]
then no gradient is displayed. Nothing. Just as if I didn't have the drawRect: method. Any ideas?
An NSGradient doesn't work with a pattern as one of the colors. That's what the exception is telling you. It will only work with an NSColor that can be converted to an RGB color. If you want to make your pattern fade to clear, you'll have to do it another way.

Why is my CGGradient not working with a preset UIColor?

I have this working code:
NSMutableArray *shadowColors = [NSMutableArray arrayWithCapacity:2];
color = [UIColor colorWithRed:0 green:0 blue:0 alpha:1]; // Declaration using components
[shadowColors addObject:(id)[color CGColor]];
color = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.0]; // Declaration using components
[shadowColors addObject:(id)[color CGColor]];
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(space, (CFArrayRef)shadowColors, NULL);
CGColorSpaceRelease(space);
CGFloat sw = 10.0; // shadow width
CGPoint top1 = CGPointMake(x, y+width/2.0);
CGPoint top2 = CGPointMake(x + sw, y+width/2.0);
CGPoint side1 = CGPointMake(x+width/2.0, y);
CGPoint side2 = CGPointMake(x+width/2.0, y+sw);
CGContextDrawLinearGradient(c, gradient, top1, top2, 0);
CGContextDrawLinearGradient(c, gradient, side1, side2, 0);
CGGradientRelease(gradient);
The color declarations are the part I'm interested in, lines 2 and 4. When I declare them as shown, they work just fine, but if I replace those two lines with the equivalent (I thought, at least) [UIColor blackColor] and [UIColor clearColor] then my gradients disappear. The colors I use don't make any difference, I can use greenColor and redColor and they still don't work.
Am I missing something or is this a bug in Apple's frameworks?
The code that doesn't work. And this is just the first section, everything else is the same.
NSMutableArray *shadowColors = [NSMutableArray arrayWithCapacity:2];
color = [UIColor blackColor];
[shadowColors addObject:(id)[color CGColor]];
color = [UIColor clearColor];
[shadowColors addObject:(id)[color CGColor]];
The code looks fine to me. blackColor and clearColor are probably both in a white color space, but the documentation says CGGradientCreateWithColors will convert the colors to the color space you pass in, so that shouldn't matter.
The only thing I can think of would be to try passing NULL for the color space, letting the gradient convert the colors to Generic RGB instead of Device RGB. This may work, but shouldn't make a difference—as far as I can see, it should work either way.
I suggest filing a bug.

Showing UIBezierPath on view

In one of my methods i have this code:
-(void)myMethod {
UIBezierPath *circle = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(75, 100, 200, 200)];
}
How do i get it to show on the view?
I tried addSubview but it gave me an incompatible type error because its expecting a UIView.
I'm sure this must be simple.
Thanks
Just thought I'd add that you don't have to necessarily draw this in a UIView's "drawRect:" method. You can draw it anywhere you'd like to provided you do it inside of a UIGraphics image context. I do this all of the time when I don't want to create a subclass of UIView. Here's a working example:
UIBezierPath *circle = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(75, 100, 200, 200)];
//you have to account for the x and y values of your UIBezierPath rect
//add the x to the width (75 + 200)
//add the y to the height (100 + 200)
UIGraphicsBeginImageContext(CGSizeMake(275, 300));
//this gets the graphic context
CGContextRef context = UIGraphicsGetCurrentContext();
//you can stroke and/or fill
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetFillColorWithColor(context, [UIColor lightGrayColor].CGColor);
[circle fill];
[circle stroke];
//now get the image from the context
UIImage *bezierImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *bezierImageView = [[UIImageView alloc]initWithImage:bezierImage];
Now just add the UIImageView as a subview.
Also, you can use this for other drawing too. Again, after a little bit of setup, it works just like the drawRect: method.
//this is an arbitrary size for example
CGSize aSize = CGSizeMake(50.f, 50.f);
//this can take any CGSize
//it works like the frame.size would in the drawRect: method
//in the way that it represents the context's size
UIGraphicsBeginImageContext(aSize);
//this gets the graphic context
CGContextRef context = UIGraphicsGetCurrentContext();
//you can do drawing just like you would in the drawRect: method
//I am drawing a square just for an example to show you that you can do any sort of drawing in here
CGContextMoveToPoint(context, 0.f, 0.f);
CGContextAddLineToPoint(context, aSize.width, 0.f);
CGContextAddLineToPoint(context, aSize.width, aSize.height);
CGContextAddLineToPoint(context, 0.f, aSize.height);
CGContextClosePath(context);
//you can stroke and/or fill
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetFillColorWithColor(context, [UIColor lightGrayColor].CGColor);
CGContextDrawPath(context, kCGPathFillStroke);
//now get the image from the context
UIImage *squareImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *squareImageView = [[UIImageView alloc]initWithImage:squareImage];
Edit: One thing I should add is that for any modern day drawing of this kind, you should be swapping out
UIGraphicsBeginImageContext(size);
for
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
This will draw your graphics correctly for retina and non retina displays.
FYI, UIGraphicsBeginImageContext(size) is equivalent to UIGraphicsBeginImageContextWithOptions(size, FALSE, 1.f) which is fine for none retina displays that may have some transparency.
However, if you don't need transparency, it is more optimized to pass in TRUE for the opaque argument.
The safest and recommended way of drawing is to pass in [[UIScreen mainScreen]scale] as the scale argument.
So for the example(s) above, you would use this instead:
UIGraphicsBeginImageContextWithOptions(aSize, FALSE, [[UIScreen mainScreen] scale]);
For more info, check out Apple's docs.
You can draw it using either fill or stroke methods for example in custom view's drawInRect: implementation:
- (void)drawRect:(CGRect)rect {
// Drawing code
UIBezierPath *circle = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(75, 100, 200, 200)];
[circle fill];
}
You can also add UIBezierPath to UIView without subclassing by using a CAShapeLayer.
For example, to add your path as a 3pt white line centered in a UIView:
UIBezierPath *mybezierpath = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(0, 0, 100, 100)];
CAShapeLayer *lines = [CAShapeLayer layer];
lines.path = mybezierpath.CGPath;
lines.bounds = CGPathGetBoundingBox(lines.path);
lines.strokeColor = [UIColor whiteColor].CGColor;
lines.fillColor = [UIColor clearColor].CGColor; /*if you just want lines*/
lines.lineWidth = 3;
lines.position = CGPointMake(self.myview.frame.size.width/2.0, self.myview.frame.size.height/2.0);
lines.anchorPoint = CGPointMake(.5, .5);
[self.myview.layer addSublayer:lines];
Drawing is the exclusive provision of views. Make a custom view, give it your path, and implement the view's drawRect: method to fill and/or stroke the path.
In Swift 2.0:
let path = UIBezierPath()
let p1 = CGPointMake(0,self.view.frame.height/2)
let p3 = CGPointMake(self.view.frame.width,self.view.frame.height/2)
path.moveToPoint(p1)
path.addQuadCurveToPoint(p3, controlPoint: CGPoint(x: self.view.frame.width/2, y: 0))
let line = CAShapeLayer()
line.path = path.CGPath;
line.strokeColor = UIColor.blackColor().CGColor
line.fillColor = UIColor.redColor().CGColor
view.layer.addSublayer(line)