iPhone - setStroke on an CGDrawArc using custom color not working - iphone

I'm drawing a full circle using arcs in Core Graphics. Each arc of the circle is a different colour. If I use standard colours (e.g. [UIColor redColor] ) it draws fine. But if I specify a custom colour (e.g. a custom red colour [UIColor colorWithRed:193 green:69 blue:57 alpha:1] ) the colour is lost and it comes out white?!
Screen shot below, I've also code there for a slight shadow and semi-transparent circle.
My code is below, its contained within the DrawRect method of my custom view. Any ideas on how I can use custom colours for the stroke of each arc?
for (DoughnutChartSliceObject *slice in _slices) {
CGContextAddArc(ctx, self.frame.size.width/2, self.frame.size.height/2, _radius, slice.startAngleInRadians, slice.endAngleInRadians, 0);
[slice.colour setStroke];
//Define line width and cap
CGContextSetLineWidth(ctx, _stroke);
CGContextSetLineCap(ctx, kCGLineCapButt);
//draw it!
CGContextDrawPath(ctx, kCGPathStroke);
}

The components of the UIColor are from 0.0 to 1.0. Thus, I think you want:
[UIColor colorWithRed:193.0/255.0 green:69.0/255.0 blue:57.0/255.0 alpha:1]

Related

Core Graphics Transparent Overlay

I'm replacing the background view of a UITableViewCell with my own custom subclass of UIView, in which I override the drawRect method with my own, which creates a multi-colored and changing background.
The problem is that when the TableViewCell is selected, the graphics under are completely hidden and it looks odd. I need to create a custom selectedBackgroundView in order to fix this. The problem is that that view needs to create a blue gradient tint over the graphics already there, and I don't know how to draw a CGRect or something similar that is partially transparent.
// Write this In your - (void)drawRect:(CGRect)rect
// To draw semi transparent Square
// Create Current Context To Draw
CGContextRef context = UIGraphicsGetCurrentContext();
UIBezierPath *square = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 100, 100)];
// following method will fill red color with alpha 0.4 last one in parameter list
// first 3 are Red, Green and Blue Respectively.
CGContextSetRGBFillColor(context, 1, 0, 0, 0.4);
[square fill];
[square stroke];

CGContext: changes the whole view color if i changed the stroke color

I am using different buttons to change the stroke color in UIBezierPath curve drawing using CGContext,but on changing color the lines drawn earlier also changes color according to the last stroke color.But i don't want the earlier drawn lines to change color.
Any help is appreciated.
I have used the following code:
(void)drawRect:(CGRect)rect{
if(colorwith==1){
CGContextRef bluecontext = UIGraphicsGetCurrentContext();
CGContextBeginPath(bluecontext); // clears any previous path
CGContextSetRGBFillColor(bluecontext, 0.2, 0.3, 0.5, .06);
CGContextSetStrokeColorWithColor(bluecontext, [UIColor blueColor].CGColor);
CGContextStrokePath(bluecontext); // draw blue line
for(UIBezierPath *_tempPath in _arrayForOperationPath)
{
[_tempPath strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
//[[UIColor blackColor]setStroke];
}
else if (colorwith==2){
CGContextRef bluecontextt = UIGraphicsGetCurrentContext();
CGContextBeginPath(bluecontextt); // clears any previous path
CGContextSetRGBFillColor(bluecontextt, 0.2, 0.8, 0.7, .01);
CGContextSetStrokeColorWithColor(bluecontextt, [UIColor redColor].CGColor);
CGContextStrokePath(bluecontextt);
// [[UIColor redColor]setStroke];
for(UIBezierPath *_tempPath in _arrayForOperationPath)
{
[_tempPath strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
//[[UIColor blackColor]setStroke];
}
}
After CGContextRef bluecontext = UIGraphicsGetCurrentContext(); add CGContextSaveGState(bluecontext); and CGContextRestoreGState(bluecontext); after you draw your bezier paths.
Your problem is that drawRect is called everytime the context updates...so everytime you draw something. You set the line color here but the previous paths already drawn don't remember RGB..just alpha ( if i remember correctly).
With CGContextSaveGState and CGContextRestoreGState you save the previous context, draw , and then restore the context as it was plus the drawing you've done.

Draw squares with Core Graphics or include pngs?

I'm making a legend for a graph that will basically look like this:
[ ] Line 1
[ ] Line 2
[ ] Line 3
The boxes on the left need to be the same color as the lines on the graph.
Anyhow, all I need to know, is whether it's faster to draw the boxes with Core Graphics or just make some pngs with GIMP for the squares and include them.
Use UIView for each legend and set their background color to the color you want.
Both approaches are fast enough that it shouldn't make a difference. However, using Core Graphics has the advantage that you're a lot more flexible, e.g. when you later decide that you need additional colors. Plus, your app will be smaller, because you don't have to include the PNG files.
Drawing boxes is a snap! I would go with Core Graphics everyday, especially since you get retina support for free.
As can be seen in this example you can do it using UIKit only classes:
// Setup colors
[myBoxColor setFill];
[myBoxBorderColor set];
// Setup a path for the box
UIBezierPath* path = [UIBezierBath bezierPathWithRect:rectOfTheBox];
path.lineWidth = 2;
// Draw!
[path fill];
[path stroke];
One warning; stroke fills using the edges of the path as the center of the line. So you will get a blurry line if you stroke a path with integral rect with a 1 point line width.
You can remedy this is you want a 1 point line for the border by doing something like this:
CGRect strokeRect = UIEdgeInsetsInsetRect(rectOfTheBox,
UIEdgeInsetsMake(0.5f,0.5f,0.5f,0.5f));
UIBezierPath* path = [UIBezierPath bezierPathWithRect:strokeRect];
[path stroke];
On iOS, Core Graphics is quite simple to use. In your view's drawRect: method, just do this to draw a square:
- (void)drawRect:(CGRect)frame {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 0.5, 0.5, 0.5, 1); // gray
CGContextFillRect(context, CGRectMake(10, 10, 20, 20)); // our rect is {10,10,20,20)
// draw a line
CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);
CGContextBeginPath(context);
CGContextMoveToPoint(context, startX, startY);
CGContextAddLineToPoint(context, endX, endY);
CGContextStrokePath(context);
}
Hope this helps!

How to use a CGBlendMode on a UIView that scrolls above a fixed background?

Our main UIView is a UIScrollView with a fixed background image (very common, obviously). In that scrollView, we have several UIViews that hold content and scroll up and down as the user scrolls (also common). Those UIViews each have their own background, a simple gradient from white to black.
The goal is to have the background gradient of those (inner) UIViews be partially opaque AND use a CGBlendMode other than "kCGBlendModeNormal" (specifically, "kCGBlendModeOverlay"). You should be able to see through to the "parent" scrollView’s fixed background image as the UIViews scroll up and down above it.
- (void)drawRect:(CGRect)rect {
gradientStart = [UIColor colorWithRed:1 green:1 blue:1 alpha:1.0];
gradientEnd = [UIColor colorWithRed:0 green:0 blue:0 alpha:1.0];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[2] = { 0.0f, 1.0f };
NSArray *colors = [NSArray arrayWithObjects:(id)gradientStart.CGColor, (id)gradientEnd.CGColor, nil];
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)colors, locations);
CGColorSpaceRelease(colorSpace);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetAlpha(context, 0.50); //this works!
CGContextSetBlendMode(context, kCGBlendModeOverlay); //doesn’t seem to do anything!
CGContextClearRect(context, rect);
CGPoint startPoint, endPoint;
startPoint.x = 0.0;
startPoint.y = 0.0;
endPoint.x = 0.0;
endPoint.y = rect.size.height;
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGGradientRelease(gradient);
[super drawRect:rect];
}
Everything works as expected except the CGContextSetBlendMode, which is ignored. We can't seem to find a way to change the blendMode of a UIView relative to what is behind it, the same way you can with alpha. Please note that this is different than building up multiple layers in a SINGLE UIView; in that case, this technique does change the blendMode of the layers "on top". We want to see through to the parent scrollView's fixed background image (as we scroll the child view up and down above it), with both an alpha and an overlay blend applied.
Here's an image showing the issue: http://img2.sbck.us/blendmode.png
Thanks in advance for your help!
I believe what you want is not possible with your current setup. On iOS, it is simply not possible for the blend mode of a view to have an effect on the stuff that is drawn under the view. You would have to draw the scroll view's background and the gradients in the same view.
This is possible, at least with two image views. It might even be possible with more general views. The approach is to implement drawRect in the parent view, and do as follows:
Determine the rect for the foreground view.
Convert the rect in the foreground view to a rect in the background view.
Begin a new graphics context.
Draw the background with the proper blend mode.
Draw the foreground with the proper blend mode.
Extract the image from the graphics context.
End the graphics context.
Use the extracted image accordingly.
This allows a foreground image to blend with a background image.
Seems like you could do this by setting the 'compositingFilter' property of your view's CALayer. The comment in CALayer.h says "A filter object used to composite the layer with its (possibly filtered) background. Default value is nil, which implies source-over compositing."
Alas, CoreImage which provides the filters is not (officially) available on iOS.
I guess your other alternative would be to use OpenGL. You could still use UIView with OpenGL after a fashion by rendering your UIView's into images which could then be used a textures.

how to draw on the surface of imageview transparently

i want to track finger touch and draw the path on top of the imageView.
following is what i did:
In the touch event:
UIgraphicsBeginImageContext(imageView.frame.size);
[imageView.image drawInRect:CGRectMake(0,0,imageView.size.width,imageView.size.height)];
//drawing.....
imageView.image=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
however, the drawing opaque the background Image?
how to drawing the path while still can make the background available?
thanks in advance:)
If you're doing simple vector drawing, you can set a color with a non-1.0 alpha value. These shapes will then be translucent when you draw them on top of your image. For example:
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGFloat values[4] = {1.0, 0.0, 0.0, 0.5};
CGColorRef translucentRed = CGColorCreate(space, values);
CGContextSetStrokeColorWithColor(context, translucentRed);
CGContextSetFillColorWithColor(context, translucentRed)
// Do your drawing here
CGColorRelease(translucentRed);
CGColorSpaceRelease(space);
will create a translucent red color and set the current stroke and fill to use that color.
Note that overlapping drawn elements will have darker areas because of this translucency, which might be an effect that you don't want.