UIColor and Graphics Context - ios

I have a custom UIView which draws a path like so
- (void)drawRect:(CGRect)rect{
[[UIColor blackColor] setStroke];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetFillColor(ctx, CGColorGetComponents(self.color));
CGContextFillPath(ctx);
UIBezierPath *thePath = [UIBezierPath bezierPath];
thePath.lineWidth = _lineWidth;
_center = CGPointMake(rect.size.width, rect.size.height);
[thePath moveToPoint:_center];
[thePath addArcWithCenter:_center radius:rect.size.width startAngle:M_PI endAngle:M_PI+degreesToRadians(_angle)clockwise:YES];
[thePath closePath];
[thePath fill];
}
My custom UIView also has a method to change the filling color
- (void) changeColor:(UIColor *) newColor {
self.color = [newColor CGColor];
[self setNeedsDisplay];
}
If I call the changeColor: method with any of the predefined colors such as
[UIColor redColor]
everything works fine. Instead if i try to give it a custom color such as
UIColor* color = [UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:1.0f];
the color of my custom UIView flicker between white, red and blue randomly.
Any ideas of why is that?
Thank you in advance!

Try:
CGContextSetFillColorWithColor(ctx, self.color.CGColor);
instead of:
CGContextSetFillColor(ctx, CGColorGetComponents(self.color));

When you are using this method call :
[UIColor redColor];
For optimization purposes, UIColor return an object with only 2 components because he don't need the other one. (This is made possible with the mechanism of Class clustering).
That's maybe why your code show some differences between this two colors.

Related

What's the difference between CGContextSetStrokeColorWithColor UIColor setStroke?

Is there any difference between those two ways of setting stroke color?
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor)
[[UIColor redColor] setStroke]
Example
CGContextRef cr = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(cr, [UIColor redColor].CGColor);
[[UIColor redColor] setStroke];
UIBezierPath *bp = [UIBezierPath new];
[bp stroke];
UIGraphicsEndImageContext();
One is longer and pure C. The other is shorter and uses Objective-C. They have the same effect.

How to draw to multiple CGLayers at the same time?

I'd like to draw objects to two separate CGLayers from within the same for loop, but am unsure how to do this.
For example, I'd like to draw three orange circles behind three blue circles, with the orange circles in one layer, and the blue circles in another. The following code will place each circle on top of the previous circle:
-(void) drawRect:(CGRect)rect {
UIBezierPath *circle;
for (int i = 1; i <= 3; i++) {
// Create an orange circle
circle = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(i*50, 80, 50, 50), 0, 0)];
circle.lineWidth = 4.0f;
[[UIColor colorWithRed:1.0 green:0.75 blue:0 alpha:1.0] setFill];
[[UIColor orangeColor] setStroke];
[circle stroke];
[circle fill];
// Create a blue circle
circle = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(25 + i*50, 80, 50, 50), 0, 0)];
circle.lineWidth = 4.0f;
[[UIColor colorWithRed:0 green:0.5 blue:1.0 alpha:1.0] setFill];
[[UIColor blueColor] setStroke];
[circle stroke];
[circle fill];
}
}
How would I modify this so that the three orange circles would end up in an orangeLayer that sits behind the three blue circles in a blueLayer? I imagine this has something to do with saving and restoring contexts, but I can't really wrap my head around it.
Thanks so much!
PS: I realize that I can simply draw using two for loops inline to achieve the right effect, but this example is for instructional purposes to learn layering. Thanks!
I build a custom subclass of UIView, and create a function makeCircleWithFrame to draw a circle inside a view using UIGraphicsBeginImageContextWithOptions, i believe it will solve your main problem:
#import "circleView.h"
#import <math.h>
#implementation circleView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) return self;
[self setupViews];
return self;
}
- (void)awakeFromNib
{
[self setupViews];
}
- (void)setupViews
{
[self setBackgroundColor:[UIColor whiteColor]];
for (int i = 1; i <= 6; i++) {
UIColor *circleColor;
//Math function just to set different colors for each circle
if (fmodf(i, 2) == 0) {
circleColor = [UIColor colorWithRed:1.0 green:0.75 blue:0 alpha:1.0];
}
else {
circleColor = [UIColor colorWithRed:0 green:0.5 blue:1.0 alpha:1.0];
}
UIView *circleView = [self makeCircleWithFrame:(CGRectMake(10*i, 10*i, 100, 100)) andFillColor:circleColor];
circleView.tag = i;
NSLog(#"circle %i", i);
}
}
- (UIView *)makeCircleWithFrame:(CGRect)rect andFillColor:(UIColor *)color {
// declare UIimageView, not UIView
UIImageView *customView = [[UIImageView alloc] init];
customView.frame= self.bounds;
// create a new contex to draw
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0);
UIBezierPath *grayCircle = [UIBezierPath bezierPathWithOvalInRect:rect];
grayCircle.lineWidth = 6;
[color setFill];
[[UIColor orangeColor] setStroke];
[grayCircle stroke];
[grayCircle fill];
customView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self addSubview:customView];
return customView;
}
Please give me a feedback if you still having problems or need anymore help.
for that purpose you need to either draw the blue or the orange circles partially (depends on which one you want to be on top). You probably understand that there are only 2 possible options: a) the orange layer is on top 2) the blue one is. I think, if you want to group the circles by color (without using 1 layer per circle), you'd better:
1) use 1 layer for drawing
2) store Bezier paths (which represent circles) somewhere
3) draw the paths in accordance to the order and overlaying you need.

Unable to make UILabel text glow

I'm running the following code in viewDidLoad, it is applying the glow outside the label not on the text. Please advise.
lbl_score.font = myfont;
lbl_score.alpha = 1.0;
lbl_score.textColor = UIColor.greenColor;
lbl_score.layer.shadowColor = [[UIColor blueColor] CGColor];
lbl_score.layer.shadowOffset = CGSizeMake(0.0, 0.0);
lbl_score.layer.shadowRadius = 30.0f;
lbl_score.layer.shadowOpacity = 0.9;
lbl_score.layer.masksToBounds = NO;
I've imported QuartzCore/QuartzCore.h". I would like to apply the glow only on the label text.
Thanks
To apply a glow to the actual text in a label, you have to override drawTextInRect on the label itself. You're setting a shadow on the label's layer, which is a rectangle.
The override is quite simple. You just adjust the graphics context, call super, then restore the graphics context:
-(void)drawTextInRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeZero, 30.0, [UIColor blueColor].CGColor);
[super drawTextInRect:rect];
CGContextRestoreGState(context);
}
You are putting a shadow on the layer, which is rectangular. UILabel has shadowColor and shadowOffset properties which you should use instead. You can’t set a separate opacity for the shadow this way, but you can bake it into the UIColor that you pass for the shadow color.
lbl_score.font = myfont;
lbl_score.alpha = 1.0;
lbl_score.textColor = UIColor.greenColor;
lbl_score.shadowColor = [[UIColor blueColor] colorWithAlphaComponent:0.9];
lbl_score.shadowOffset = CGSizeMake(0.0, 0.0);
Unfortunately, you can’t set a shadow radius in this way. If you need to change the radius, look at doing your own custom drawing in -drawRect: instead.
I found code similar to jrturton ,but with more customisation.
This is working for me.
DTGlowingLabel.h
#interface DTGlowingLabel : UILabel {
}
#end
DTGlowingLabel.m
#import "DTGlowingLabel.h"
#implementation DTGlowingLabel
- (void) drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIColor *insideColor = [UIColor colorWithRed:69.0/255.0 green:254.0/255.0 blue:0 alpha:1];
UIColor *outlineColor = [UIColor colorWithRed:22.0/255.0 green:145.0/255.0 blue:0 alpha:0.8];
UIColor *blurColor = [UIColor colorWithRed:104.0/255.0 green: 248.0/255.0 blue:0 alpha:0.7];
CGContextSetStrokeColorWithColor(ctx, outlineColor.CGColor);
CGContextSetFillColorWithColor(ctx, insideColor.CGColor);
CGContextSetLineWidth(ctx, self.font.pointSize/60.0);
CGContextSetShadowWithColor(ctx, CGSizeMake(0, 0), self.font.pointSize / 10.0, blurColor.CGColor);
CGContextSetTextDrawingMode(ctx, kCGTextFillStroke);
[self.text drawInRect:self.bounds withFont:self.font lineBreakMode:self.lineBreakMode alignment:self.textAlignment];
}
#end
Source : http://www.cocoanetics.com/2010/01/uilabels-with-neon-effect/

iOS: Draw clear circle with UIBezierPath bezierPathWithOvalInRect:

In my UITableViewController's cells, I want to display a circle with a number in it. I am using UIBezierPath's bezierPathWithOvalInRect: to draw the circle.
Unfortunately, while I can set the fill color to be clearColor, the unused portion of the CGRect passed to bezierPathWithOvalInRect: is black.
How do I get rid of the black area created?
Partial screenshot for reference:
(I eventually hope to get that number inside the circle)
Code:
LTTTableViewCell:
- (void)awakeFromNib {
[super awakeFromNib];
// Create a square view using the height of the cell
CGRect positionFrame = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.height);
LTTDrawBallView *drawBallView = [[LTTDrawBallView alloc] initWithFrame:positionFrame];
[self.contentView addSubview:drawBallView];
}
LTTDrawBallView:
- (void)drawRect:(CGRect)rect
{
// Create a new rect with some padding
// + create a circle from this new rect:
CGRect box = CGRectInset(self.bounds, self.bounds.size.width * 0.1f, self.bounds.size.height * 0.1f);
UIBezierPath *ballBezierPath = [UIBezierPath bezierPathWithOvalInRect:box];
[[UIColor whiteColor] setStroke];
[[UIColor greenColor] setFill]; // Green here to show the black area
[ballBezierPath stroke];
[ballBezierPath fill];
[self setBackgroundColor:[UIColor clearColor]]; // Happens with and without this line
}
In the init method of your LTTDrawBallView, include the code:
self.opaque = NO;
self.backgroundColor = [UIColor clearColor];

Quartz 2D Drawing Crashing

I don't know why this stopped working, but this chunk of code is crashing my device when I try drawing any part of it. I'm new to core graphics so any pointers or suggestions would be a great help. Thanks!
// Style
CGContextRef context = UIGraphicsGetCurrentContext();
// Colors
CGColorRef fillBox = [UIColor colorWithRed:250.0/255.0 green:250.0/255.0 blue:250.0/255.0 alpha:1.0].CGColor;
CGColorRef fillBoxShadow = [UIColor colorWithRed:77.0/255.0 green:77.0/255.0 blue:77.0/255.0 alpha:1.0].CGColor;
CGRect box = CGRectMake(5, 5, self.frame.size.width - 10, self.frame.size.height - 10);
// Shadow
CGContextSetShadowWithColor(context, CGSizeMake(0, 0), 1.0, fillBoxShadow);
CGContextAddRect(context, box);
CGContextFillPath(context);
// Box
CGContextSetFillColorWithColor(context, fillBox);
CGContextAddRect(context, box);
CGContextFillPath(context);
If your project is using ARC, then these two lines might be part of your problem:
CGColorRef fillBox = [UIColor colorWithRed:250.0/255.0 green:250.0/255.0 blue:250.0/255.0 alpha:1.0].CGColor;
CGColorRef fillBoxShadow = [UIColor colorWithRed:77.0/255.0 green:77.0/255.0 blue:77.0/255.0 alpha:1.0].CGColor;
ARC is releasing the UIColor object and thus the CGColorRef. You need to retain the CGColorRef and then release it when you are done with it.
I would write the code something like this:
UIColor *fillBox = [UIColor colorWithRed:250.0/255.0 green:250.0/255.0 blue:250.0/255.0 alpha:1.0];
UIColor *fillBoxShadow = [UIColor colorWithRed:77.0/255.0 green:77.0/255.0 blue:77.0/255.0 alpha:1.0];
and then use fillBox.CGColor and fillBoxShadow.CGColor later on in the method.
Instead of doing
CGContextAddRect(context, box);
CGContextFillPath(context);
Try using CGContextFillRect.
You can't fill a path you haven't added to the context beforehand.
Note: you could do
CGContextAddPath(context, [UIBezierPath pathWithRect:box].CGPath);
CGContextFillPath(context);
but that's a bit overkill compared to just filling a rect.
(Not sure about the pathWithRect: syntax, but it exists.)

Resources