Making a layer structure for a drawing application - iphone

In relation to question an eralier question of mine, I have tried and failed to create a class with a NSMuttableArray member variable holding CALayerRefs. Can someone please guide me on how to do that. What I want to do is basically create CALayerRefs or CGLayerRefs or whatever, push them into my layers variable, and then, when I need them, fetch, use their context and finally draw/hide/show/delete them.
I turn to you, guys, because apparently, there is few to none information on the net on working with layers and Quartz on an advanced level. Everybody uses the layers right away, no management needed, no member variables.
Thank you.

Here's some working code for custom view I wrote in few minutes, hope it helps. It creates 10 green layers, and animates them each second to different locations.
MBLineLayerDelegate *lineLayerDelegate;
#property (nonatomic, retain) NSMutableArray *ballLayers;
- (void)awakeFromNib
{
self.ballLayers = [NSMutableArray array];
lineLayerDelegate = [[MBLineLayerDelegate alloc] init];
for (NSUInteger i = 0; i < 10; i++) {
CALayer *ball = [CALayer layer];
CGFloat x = self.bounds.size.width * (CGFloat)random()/RAND_MAX;
CGFloat y = self.bounds.size.height * (CGFloat)random()/RAND_MAX;
ball.frame = CGRectMake(x, y, 20, 20);
ball.backgroundColor = [UIColor greenColor].CGColor;
ball.delegate = lineLayerDelegate;
[self.layer addSublayer:ball];
[self.ballLayers addObject:ball];
}
[self performSelector:#selector(animateBallsToRandomLocation) withObject:nil afterDelay:0];
}
- (void)animateBallsToRandomLocation
{
for (CALayer *layer in self.ballLayers) {
CGFloat x = self.bounds.size.width * (CGFloat)random()/RAND_MAX;
CGFloat y = self.bounds.size.height * (CGFloat)random()/RAND_MAX;
layer.position = CGPointMake(x, y);
}
[self performSelector:#selector(animateBallsToRandomLocation) withObject:nil afterDelay:1];
}
Here's some code for CALayer's delegate that draws a line:
#interface MBLineLayerDelegate : NSObject {
}
- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx;
#end
#implementation MBLineLayerDelegate
- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{
CGRect rect = layer.bounds;
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, rect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetAllowsAntialiasing(context, YES);
CGContextSetShouldAntialias(context, YES);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, rect.size.width, rect.size.height);
CGContextRestoreGState(context);
}
#end

Related

Subclassing UIScrollview

I have been trying desperately to draw some images into a view. The view should be inside a scrollview. For that I subclassed UIScrollview and override the drawRect method in it. And added this as my UIView's subview.
#interface DrawAnotherViewClass : UIScrollView<UIScrollViewDelegate> {
}
#end
#implementation DrawAnotherViewClass
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
CGRect fullScreenRect=[[UIScreen mainScreen] applicationFrame];
self.frame = fullScreenRect;
self.contentSize = CGSizeMake(600, 600);
self.showsHorizontalScrollIndicator = YES;
self.showsVerticalScrollIndicator = NO;
self.pagingEnabled = YES;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextMoveToPoint(context, 10.0f, 50.0f);
CGContextAddLineToPoint(context, 10.0f, 200.0f);
CGContextStrokePath(context);
CGContextMoveToPoint(context, 8.0f, 77.0f);
CGContextAddLineToPoint(context, 300.0f, 77.0f);
CGContextStrokePath(context);
CGContextSetRGBFillColor(context, 0, 0, 255, 0.1);
CGContextSetRGBStrokeColor(context, 0, 0, 255, 1);
CGContextStrokeEllipseInRect(context, CGRectMake(65.0, 33.5, 25, 25));
UIImage *image1 = [UIImage imageNamed:#"PinDown1.png"];
UIImage *image2 = [UIImage imageNamed:#"pinGreen_v1.png"];
CGPoint drawPoint = CGPointMake(0.0f, 10.0f);
[image2 drawAtPoint:drawPoint];
for(int i =1; i<20; i++){
CGPoint drawPointOne = CGPointMake(40.0f * i, 40.0f);
[image1 drawAtPoint:drawPointOne];
}
}
Am I missing something here. Is this the right way to go.
If the view that should perform the drawing resides in that UIScrollView, you have to put the - (void)drawRect:(CGRect)rect method into that view's class method and not into the UIScrollView subclass.

UIView's drawRect is not getting called

I am trying to display horizontal and/or vertical lines in a grid. So I created a UIView subclass GridLines that draws lines in drawRect:. I then create two of these (one vertical, one not), and add them as subviews to my primary view (Canvas) also UIView derived. The other custom subviews I add to Canvas are displayed, removed, etc. properly, but the GridLines objects are not, and their drawRect:s never get called. When I had this line-drawing code in [Canvas drawRect:] (which is now disabled), it displayed the grid properly.
Looking through similar questions, it seems most people with this issue are calling drawRect in a non-UIView derived class, but mine is a UIView.
Am I missing something here?
GridLines.h:
#import <UIKit/UIKit.h>
#interface GridLines : UIView
{
BOOL mVertical;
}
- (id) initWithFrame: (CGRect) _frame vertical: (BOOL) _vertical;
#end
GridLines.m:
#import "GridLines.h"
#implementation GridLines
- (id) initWithFrame: (CGRect) _frame vertical: (BOOL) _vertical
{
if ((self = [super initWithFrame: _frame]))
{
mVertical = _vertical;
}
return self;
}
- (void) drawRect: (CGRect) _rect
{
NSLog(#"[GridLines drawRect]");
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor clearColor] set];
UIRectFill([self bounds]);
if (mVertical)
{
for (int i = 50; i < self.frame.size.width; i += 50)
{
CGContextBeginPath(context);
CGContextMoveToPoint(context, (CGFloat)i, 0.0);
CGContextAddLineToPoint(context, (CGFloat)i, self.frame.size.height);
[[UIColor grayColor] setStroke];
CGContextSetLineWidth(context, 1.0);
CGContextDrawPath(context, kCGPathFillStroke);
}
}
else
{
for (int j = 50; j < self.frame.size.height; j += 50)
{
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0, (CGFloat)j);
CGContextAddLineToPoint(context, self.frame.size.width, (CGFloat)j);
[[UIColor grayColor] setStroke];
CGContextSetLineWidth(context, 1.0);
CGContextDrawPath(context, kCGPathFillStroke);
}
}
}
#end
In another UIView derived class:
- (void) createGrids
{
mHorizontalLines = [[GridLines alloc] initWithFrame: self.frame vertical: NO];
mVerticalLines = [[GridLines alloc] initWithFrame: self.frame vertical: YES];
[self addSubview: mHorizontalLines];
[self addSubview: mVerticalLines];
}
You may have a frame v bounds problem.
mHorizontalLines = [[GridLines alloc] initWithFrame: self.frame vertical: NO];
mVerticalLines = [[GridLines alloc] initWithFrame: self.frame vertical: YES];
frame is kept in superview's co-ordinate space, if self.frame is offset more that it is wide, when you set these new views to that frame, they'll be clipped to rect of self.
try changing this to self.bounds, which should have origin = {0,0}

Quartz 2d trying to redraw a triangle

I'm developing an iPhone app.
I have the following class:
#import "Triangulo.h"
#implementation Triangulo
#synthesize minusValue;
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
CGSize size = rect.size;
CGPoint origin = {10.0f, size.height - 10.0f};
[self drawLineAtOrigin:origin withLength:size.width - 10.0f];
CGPoint origin2 = {10.0f, size.height - 20.0f};
CGSize size2 = {size.width - minusValue, 20.0f};
[self drawTriangleAtOrigin:origin2 withSize: size2 inRect: rect];
}
- (void)drawLineAtOrigin:(CGPoint)origin withLength:(float)length {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGContextMoveToPoint(context, origin.x, origin.y);
CGContextAddLineToPoint(context, length, origin.y);
CGContextStrokePath(context);
}
- (void)drawTriangleAtOrigin:(CGPoint)origin withSize:(CGSize)size inRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(UIGraphicsGetCurrentContext(), rect);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextMoveToPoint(context, origin.x, origin.y);
CGContextAddLineToPoint(context, size.width, origin.y);
CGContextAddLineToPoint(context, size.width, origin.y - size.height);
CGContextAddLineToPoint(context, origin.x, origin.y);
CGContextFillPath(context);
CGContextStrokePath(context);
}
- (void)dealloc {
[super dealloc];
}
#end
This UIView is part of UIViewController.view. I've add in UIViewController.h as:
IBOutlet Triangulo *triangulo;
...
#property (nonatomic, retain) IBOutlet Triangulo *triangulo;
On UIViewController I have a button to modify Triangulo:
- (IBAction)btnDrawTriangleClicked:(id)sender {
triangulo.minusValue += 10.0f;
CGRect rect = CGRectMake(0, 0, 280, 50);
[triangulo drawRect: rect];
}
But I can't draw anything because UIGraphicsGetCurrentContext is always nil.
Any advice?
Add this code to your Triangulo class:
- (void)setMinusValue:(double)aMinusValue {
minusValue = aMinusValue;
[self setNeedsDisplay];
}
And then the btnDrawTriangleClicked: method to the following:
- (IBAction)btnDrawTriangleClicked:(id)sender {
triangulo.minusValue += 10.0f;
}
Now when you alter the minusValue, Triangulo automatically flags itself as needing redisplay. (See The View Drawing Cycle for more info). As Deepak stated, you never call drawRect: yourself (unless you're within the drawRect: method itself, and you're calling [super drawRect:frame];). The drawRect: method is called automatically by the system, and it always makes sure that a valid CGGraphicsContext is set up beforehand. Since you were calling it directly, that preparation work wasn't being done, so UIGraphicsGetCurrentContext() usually returned NULL.
You should never call drawRect: directly. You should call either setNeedsDisplay or setNeedsDisplayInRect: whenever you want to redraw the view. rect that is passed to drawRect: is not a random value that is passed. It tells you the portion of the view's bounds that need to be redrawn.

Draw part of a circle

For an iPhone application I want to draw a circle, that is only for an x percentage filled.
Something like this:
I have no problems calculating the radius, the degrees or the radians, that is no problem. Also drawing the circle is already done. But how do I get the iPhone SDK to draw the part that is filled.
I can draw a rectangle that size, but not part of a circle.
I just want to draw that on a a normal context.
Hope someone can give me any pointers here.
A lot of people have showed you how this can be done in Core Graphics but it can also be done with Core Animation which gives the big addition of easily being able to animate the percentage of the pie shape.
The following code will create both the ring and the partly filled layers (even though you said that you already can draw the ring) since its nice to have both the ring and the pie shape to be drawn using the same method.
If you animate the strokeStart or strokeEnd properties of the pieShape layer you will have the percentage animate. As with all Core Animation code you will need to add QuartzCore.framework to your project and include <QuartzCore/QuartzCore.h> in your code.
// Create a white ring that fills the entire frame and is 2 points wide.
// Its frame is inset 1 point to fit for the 2 point stroke width
CGFloat radius = MIN(self.frame.size.width,self.frame.size.height)/2;
CGFloat inset = 1;
CAShapeLayer *ring = [CAShapeLayer layer];
ring.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
cornerRadius:radius-inset].CGPath;
ring.fillColor = [UIColor clearColor].CGColor;
ring.strokeColor = [UIColor whiteColor].CGColor;
ring.lineWidth = 2;
// Create a white pie-chart-like shape inside the white ring (above).
// The outside of the shape should be inside the ring, therefore the
// frame needs to be inset radius/2 (for its outside to be on
// the outside of the ring) + 2 (to be 2 points in).
CAShapeLayer *pieShape = [CAShapeLayer layer];
inset = radius/2 + 2; // The inset is updated here
pieShape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
cornerRadius:radius-inset].CGPath;
pieShape.fillColor = [UIColor clearColor].CGColor;
pieShape.strokeColor = [UIColor whiteColor].CGColor;
pieShape.lineWidth = (radius-inset)*2;
// Add sublayers
// NOTE: the following code is used in a UIView subclass (thus self is a view)
// If you instead chose to use this code in a view controller you should instead
// use self.view.layer to access the view of your view controller.
[self.layer addSublayer:ring];
[self.layer addSublayer:pieShape];
Use CGContext's arc functions:
CGContextAddArc(context,
centerX,
centerY,
radius,
startAngleRadians,
endAngleRadians,
clockwise ? 1 : 0);
See the documentation for CGContextAddArc().
Try this:
CGContextMoveToPoint(the center point)
CGContextAddLineToPoint(the starting point of the fill path on the circumference)
CGContextAddArcToPoint(the ending point of the fill path on the circumference)
CGContextAddLineToPoint(the center point)
CGContextFillPath
I implemented a pie progress view that looks similar to what you are doing. It's open source. Hopefully the source code will help.
SSPieProgressView.h source
SSPieProgressView.m source
CircleViewController.h
#import <UIKit/UIKit.h>
#interface CircleViewController : UIViewController
#end
CircleViewController.m
#import "CircleViewController.h"
#import "GraphView.h"
#interface CircleViewController ()
#end
#implementation CircleViewController
- (void)viewDidLoad {
[super viewDidLoad];
GraphView *graphView = [[GraphView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
graphView.backgroundColor = [UIColor whiteColor];
graphView.layer.borderColor = [UIColor redColor].CGColor;
graphView.layer.borderWidth = 1.0f;
[self.view addSubview:graphView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
GraphView.h
#import <UIKit/UIKit.h>
#interface GraphView : UIView
#end
GraphView.m
#import "GraphView.h"
#implementation GraphView
- (void)drawRect:(CGRect)rect {
CGPoint circleCenter = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
[self drawCircleWithCircleCenter:(CGPoint) circleCenter radius:80 firstColor:[UIColor blueColor].CGColor secondeColor:[UIColor redColor].CGColor lineWidth:2 startDegree:0 currentDegree:90];
//[self drawCircleWithCircleCenter2:(CGPoint) circleCenter radius:80 firstColor:[UIColor blueColor].CGColor secondeColor:[UIColor redColor].CGColor lineWidth:2 startDegree:0 currentDegree:90];
}
- (void)drawCircleWithCircleCenter:(CGPoint) circleCenter
radius:(CGFloat)radius
firstColor:(CGColorRef)firstColor
secondeColor:(CGColorRef)secondeColor
lineWidth:(CGFloat)lineWidth
startDegree:(float)startDegree
currentDegree:(float)endDegree {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, lineWidth);
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);
CGContextAddArc(context, circleCenter.x , circleCenter.y, radius, [self radians:startDegree], [self radians:endDegree], 0);
CGContextSetFillColorWithColor(context, firstColor);
CGContextFillPath(context);
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);
CGContextAddArc(context, circleCenter.x, circleCenter.y, radius, [self radians:endDegree], [self radians:startDegree], 0);
CGContextSetFillColorWithColor(context, secondeColor);
CGContextFillPath(context);
}
- (void)drawCircleWithCircleCenter2:(CGPoint) circleCenter
radius:(CGFloat)radius
firstColor:(CGColorRef)firstColor
secondeColor:(CGColorRef)secondeColor
lineWidth:(CGFloat)lineWidth
startDegree:(float)startDegree
currentDegree:(float)endDegree {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, lineWidth);
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);
CGContextAddArc(context, circleCenter.x , circleCenter.y, radius, [self radians:startDegree], [self radians:endDegree], 0);
CGContextSetFillColorWithColor(context, firstColor);
CGContextFillPath(context);
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);
CGContextAddArc(context, circleCenter.x, circleCenter.y, radius, [self radians:endDegree], [self radians:startDegree], 0);
CGContextSetStrokeColorWithColor(context, secondeColor);
CGContextStrokePath(context);
}
-(float) radians:(double) degrees {
return degrees * M_PI / 180;
}
#end
note: you can use one of the 2 methods:
"drawCircleWithCircleCenter" or "drawCircleWithCircleCenter2"
this code if you want to split cell on 2 parts only
if you want to split cell on more than 2 parts you can check this : "Drawing a circle ,filled different parts with different color" and check the answer start with this Phrase "we have 6 class"
Well, since nobody used NSBezierPath so far, I figured I could provide the solution I recently used for the same problem:
-(void)drawRect:(NSRect)dirtyRect
{
double start = -10.0; //degrees
double end = 190.0; //degrees
NSPoint center = NSMakePoint(350, 200);
double radius = 50;
NSBezierPath *sector = [NSBezierPath bezierPath];
[sector moveToPoint:center];
[sector appendBezierPathWithArcWithCenter:center radius:radius startAngle:start endAngle:end];
[sector lineToPoint:center];
[sector fill];
}
Below is a full method I am using that does this with Core Graphics, adapting and expanding on mharper's comment above.
This code is for OSX Cocoa, but could easily be changed to iOS, by modifying how you get the context.
- (void)drawPieShapedCircleWithRadius:(CGFloat)radius
strokeColor:(CGColorRef)strokeColor
fillColor:(CGColorRef)fillColor
lineWidth:(CGFloat)lineWidth
currentDegrees:(float)currentDegrees
startDegrees:(float)startDegrees {
// get the context
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
// Set the color of the circle stroke and fill
CGContextSetStrokeColorWithColor(context, strokeColor);
CGContextSetFillColorWithColor(context, fillColor);
// Set the line width of the circle
CGContextSetLineWidth(context, 1);
// Calculate the middle of the circle
CGPoint circleCenter = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
// Move the bezier to the center of the circle
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y); // move to the center point
// Draw the arc from the start point (hardcoded as the bottom of the circle) to the center
CGContextAddLineToPoint(context, circleCenter.x, circleCenter.y + radius);
// Draw the arc around the circle from the start degrees point to the current degrees point
CGContextAddArc(context, circleCenter.x , circleCenter.y, radius, [self radians:startDegrees], [self radians:startDegrees + currentDegrees], 0);
// Draw the line back into the center of the circle
CGContextAddLineToPoint(context, circleCenter.x, circleCenter.y);
// Fill the circle
CGContextFillPath(context);
// Draw the line around the circle
CGContextStrokePath(context);
}
Try this code in a UIView, Example "MyChartClass"...
- (void)drawRect:(CGRect)rect {
int c=(int)[itemArray count];
CGFloat angleArray[c];
CGFloat offset;
int sum=0;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetAllowsAntialiasing(context, false);
CGContextSetShouldAntialias(context, false);
for(int i=0;i<[itemArray count];i++) {
sum+=[[itemArray objectAtIndex:i] intValue];
}
for(int i=0;i<[itemArray count];i++) {
angleArray[i]=(float)(([[itemArray objectAtIndex:i] intValue])/(float)sum)*(2*3.14);
CGContextMoveToPoint(context, radius, radius);
if(i==0)
CGContextAddArc(context, radius, radius, radius, 0,angleArray[i], 0);
else
CGContextAddArc(context, radius, radius, radius,offset,offset+angleArray[i], 0);
offset+=angleArray[i];
CGContextSetFillColorWithColor(context, ((UIColor *)[myColorArray objectAtIndex:i]).CGColor);
CGContextClosePath(context);
CGContextFillPath(context);
}
}
Implementation in your UIViewController
MyChartClass *myChartClass=[[MyChartClass alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];
myChartClass.backgroundColor = [UIColor clearColor];
myChartClass.itemArray=[[NSArray alloc]initWithObjects:#"75",#"25", nil];
myChartClass.myColorArray=[[NSArray alloc]initWithObjects:[UIColor blackColor],[UIColor whiteColor], nil];
myChartClass.radius=100;
[self.view addSubview:myChartClass];
Regards.

Using CAGradientLayer as backround while also drawing in context with drawRect:

I'm writing an app that plots some data into a simple graph and sometimes want to draw out the scale in the background. To do this I have a UIView subclass which acts as the graph background and simply use the drawRect: method to draw the scale (data elements will get added as subviews to this view, since I want the user to be able to interact with them).
However, I also want a gradient background color and have used CAGradientLayer for this purpose (as suggested in this thread). But when I add this as a sublayer, the gradient background appears, but nothing I do in drawRect: shows!
I'm sure I'm missing something simple or have misunderstood how to use CAGradientLayer or something, so any help or suggestions is appreciated!
This is the relevant code in my UIView subclass:
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Create a gradient background
CAGradientLayer *gradientBackground = [CAGradientLayer layer];
gradientBackground.frame = self.bounds;
gradientBackground.colors = [NSArray arrayWithObjects:(id)[[UIColor grayColor] CGColor], (id)[[UIColor whiteColor] CGColor], nil];
[self.layer insertSublayer:gradientBackground atIndex:0];
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Get the graphics context
CGContextRef context = UIGraphicsGetCurrentContext();
// Clear the context
CGContextClearRect(context, rect);
// Call actual draw method
[self drawInContext:context];
}
-(void)drawInContext:(CGContextRef)context {
CGFloat step;
// Draw Y scale
if (displayYScale) {
CGContextSetRGBStrokeColor(context, 0, 0, 0, kScaleLineAlpha);
if (yAxisScale.mode == FCGraphScaleModeData) {
step = (self.frame.size.height-(yAxisScale.padding*2))/yAxisScale.dataRange.maximum;
for (int i = 0; i <= yAxisScale.dataRange.maximum; i++) {
CGContextMoveToPoint(context, 0.0f, (step*i)+yAxisScale.padding);
CGContextAddLineToPoint(context, self.frame.size.width, (step*i)+yAxisScale.padding);
}
} else if (yAxisScale.mode == FCGraphScaleModeDates) {
int units = (int)[yAxisScale units];
step = (self.frame.size.height-(yAxisScale.padding*2))/units;
for (int i = 0; i <= units; i++) {
CGContextMoveToPoint(context, 0.0f, (step*i)+yAxisScale.padding);
CGContextAddLineToPoint(context, self.frame.size.width, (step*i)+yAxisScale.padding);
}
}
CGContextStrokePath(context);
}
// Draw X scale
if (displayXScale) {
CGContextSetRGBStrokeColor(context, 0, 0, 255, kScaleLineAlpha);
if (xAxisScale.mode == FCGraphScaleModeData) {
step = (self.frame.size.width-(xAxisScale.padding*2))/xAxisScale.dataRange.maximum;
for (int i = 0; i <= xAxisScale.dataRange.maximum; i++) {
CGContextMoveToPoint(context, (step*i)+xAxisScale.padding, 0.0f);
CGContextAddLineToPoint(context, (step*i)+xAxisScale.padding, self.frame.size.height);
}
} else if (xAxisScale.mode == FCGraphScaleModeDates) {
int units = (int)[xAxisScale units];
step = (self.frame.size.width-(xAxisScale.padding*2))/units;
for (int i = 0; i <= units; i++) {
CGContextMoveToPoint(context, (step*i)+xAxisScale.padding, 0.0f);
CGContextAddLineToPoint(context, (step*i)+xAxisScale.padding, self.frame.size.height);
}
}
CGContextStrokePath(context);
}
}
Thanks!
/Anders
Since you're drawing anyway, you can also just draw your own gradient:
// the colors
CGColorRef topColor = [[UIColor grayColor] CGColor];
CGColorRef bottomColor = [[UIColor whiteColor] CGColor];
NSArray *colors =
[NSArray arrayWithObjects: (id)topColor, (id)bottomColor, nil];
CGFloat locations[] = {0, 1};
CGGradientRef gradient =
CGGradientCreateWithColors(CGColorGetColorSpace(topColor),
(CFArrayRef)colors, locations);
// the start/end points
CGRect bounds = self.bounds;
CGPoint top = CGPointMake(CGRectGetMidX(bounds), bounds.origin.y);
CGPoint bottom = CGPointMake(CGRectGetMidX(bounds), CGRectGetMaxY(bounds));
// draw
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawLinearGradient(context, gradient, top, bottom, 0);
CGGradientRelease(gradient);
Sublayers will show above anything done in drawRect. Add another sublayer on top of the gradient layer that uses your view as the delegate, in that layers drawLayer:inContext: callback do what you're currently doing in drawRect.