Problem in draw rect - iphone

I use below code in viewLoad (i don't want to draw in - (void)drawRect:(CGRect)rect)for add rect on view but doesn't work.why?
CGRect rect=CGRectMake(10,10,150,140);
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat red[4] = {1.0f, 0.0f, 0.0f, 1.0f};
CGContextSetStrokeColor(context, red);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 10, 10);
CGContextAddRect(context, rect);
CGContextStrokePath(context);

You can only draw when you've got a drawing context. You can either create an image context anywhere you like to create an image, or you can draw inside drawRect: to draw to your view. You are not supposed to draw to your view outside of drawRect:.
It might look like you're getting a context, but in fact you don't as UIGraphicsGetCurrentContext() returns nil outside of drawRect: (or to be more correct: it only returns a context inside drawRect: or if you've created and pushed an image context yourself).

UIGraphicsGetCurrentContext() will return nil when there is no current context. A context is created for you before drawRect: is called; if you want to create a context manually, use UIGraphicsBeginImageContext or UIGraphicsBeginImageContextWithOptions to start one, UIGraphicsGetImageFromCurrentImageContext() to extract the UIImage, and UIGraphicsEndImageContext() when you're done with it to release the context. See the documentation for details.
You could also, of course, create a CGBitmapContextRef and use CoreGraphics calls directly rather than UIKit calls. There are pros and cons to each approach, the major difference being the default transformation matrix.

Related

How to Render a rotated UIlabel

I'm currently developing an app like photoshop for iPad and when i want flatten my array of layers, DrawTextInRect doesn't preserve the Transform (CAAffineTransformMakeRotation) of my UILabel. Anybody have any idea?
Draw your text into another context and get a CGImage of it, then see if drawing the image in your rotated context will work (it should).
EDIT: I have not done this myself, I believe it will work. The label probably should not be inserted into a view when you do this, but it might work that way anyway. You may have to experiment:
UIGraphicsBeginImageContextWithOptions( myLabel.bounds.size, NO, 0); // 0 == [UIScreen mainScreen].scale
CGContextRef context = UIGraphicsGetCurrentContext();
[myLabel.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Translate the context to the label's origin, and then apply the label's transform to the context.
The code below is in Swift.
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
let t = myLabel.transform
let translationPt = CGPoint.init(x: myLabel.frame.origin.x, y: myLabel.frame.origin.y)
context.translateBy(x: translationPt.x, y: translationPt.y)
context.concatenate(t)
myLabel.layer.render(in: context)
context.restoreGState()

Problem in drawing square in sample app

Hi i am making a sample app in which i wanto create a square for which i used the following code
- (void)viewDidLoad {
[super viewDidLoad];
[self drawRect:CGRectMake(0, 0, 300, 200)];
[[self view] setNeedsDisplay];
}
- (void) drawRect:(CGRect)rect
{
NSLog(#"drawRect");
CGFloat centerx = rect.size.width/2;
CGFloat centery = rect.size.height/2;
CGFloat half = 100/2;
CGRect theRect = CGRectMake(-half, -half, 100, 100);
// Grab the drawing context
CGContextRef context = UIGraphicsGetCurrentContext();
// like Processing pushMatrix
CGContextSaveGState(context);
CGContextTranslateCTM(context, centerx, centery);
// Uncomment to see the rotated square
//CGContextRotateCTM(context, rotation);
// Set red stroke
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
{
CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 1.0);
}
// Draw a rect with a red stroke
CGContextFillRect(context, theRect);
CGContextStrokeRect(context, theRect);
// like Processing popMatrix
CGContextRestoreGState(context);
[[self view] setNeedsDisplay];
}
But nothing is drawn on screen , dont know wheres the issue is .When i debug it the CGContextRef context was always 0x0 , i dont know why its 0x0 always am i missing something in my code.
It looks like you're trying to draw in a subclass of UIViewController. You need to subclass UIView to override the drawRect: method, which is then called automatically with a valid graphics context in place. You almost never call this method yourself.
To quote the Apple docs:
"To draw to the screen in an iOS application, you set up a UIView object and implement its drawRect: method to perform drawing. The view’s drawRect: method is called when the view is visible onscreen and its contents need updating. Before calling your custom drawRect: method, the view object automatically configures its drawing environment so that your code can start drawing immediately. As part of this configuration, the UIView object creates a graphics context (a CGContextRef opaque type) for the current drawing environment. You obtain this graphics context in your drawRect: method by calling the UIKit function UIGraphicsGetCurrentContext."
So essentailly, your code is on track, you just need to get it in the right place. It needs to be in the View object.

iPhone - How to draw something in a view

I'v got this piece of code :
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGFloat colors[] = {
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
};
CGGradientRef gradientRef = CGGradientCreateWithColorComponents(rgb, colors, NULL, sizeof(colors) / (sizeof(colors[0]) * 4));
CGColorSpaceRelease(rgb);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = theCell.backgroundView.bounds;
CGPoint start = CGPointMake(rect.origin.x, 0);
CGPoint end = CGPointMake(rect.origin.x, rect.size.height/2);
CGContextDrawLinearGradient(context, gradientRef, start, end, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
And I wonder how I can make it draw into a designated view and a clipping rect passed in parameters to my function. Tip: I don't mind about drawRect, I'm not subclassing anything.
Tip 2: I don't want to insert any layers that I won't be able to remove later.
Tip 3: This piece of code does not draw anything that my eyes could see..... :-( Missing a graphic port ?
Tip 4: I'd like to erase the draw simply changing the background color, and it's done...
CGContextRef context = UIGraphicsGetCurrentContext(); will get the graphics context for the current view, so if you call this in the drawRect: method of a UIView it will draw.
I don't understand what you mean by:
I don't mind about drawRect, I'm not
subclassing anything
but if you want to do custom drawing you must either override the drawRect: method or use layers. To use layers you would call CGContextRef context = CGLayerGetContext(theLayer); instead of CGContextRef context = UIGraphicsGetCurrentContext();.
Ok, so I looked at the documentation and it says that you can get a CGContextRef by calling UIGraphicsGetCurrentContext() from the drawRectMethod. Here's what it says: In an iOS application, you set up a UIView object to draw to and implement the drawRect: method to perform drawing. Before calling your custom drawRect: method, the view object automatically configures its drawing environment so that your code can start drawing immediately. As part of this configuration, the UIView object creates a graphics context (a CGContextRef opaque type) for the current drawing environment. You obtain this graphics context by calling the UIKit function UIGraphicsGetCurrentContext. You save and restore graphics contexts using the functions UIGraphicsPushContext and UIGraphicsPopContext.
You can create custom graphics context objects in situations where you want to draw somewhere other than your view. For example, you may want to capture a series of drawing commands and use them to create an image or a PDF file. To create the context, you use the CGBitmapContextCreate or CGPDFContextCreate function. After you have the context, you can pass it to the drawing functions needed to create your content.
When creating custom contexts, the coordinate system for those contexts is different from the native coordinate system used by iOS. Instead of the origin being in the upper-left corner of the drawing surface, it is in the lower-left corner and the axes point up and to the right. The coordinates you specify in your drawing commands must take this into consideration or the resulting image or PDF file may appear wrong when rendered. See “Creating a Bitmap Graphics Context” and “Creating a PDF Graphics Context” for details on using CGBitmapContextCreate and CGPDFContextCreate.
Might I recommend you look into the CAGradientLayer, and add it as a sublayer of your view? Lots simpler, and it will be hardware accelerated which matters for table cells.
Example stolen partly from here:
http://tumbljack.com/post/188089679/gpu-accelerated-awesomeness-with-cagradientlayer
#import <QuartzCore/QuartzCore.h> // Also import this framework
......
CAGradientLayer grad = [CAGradientLayer layer];
UIColor *colorOne = [UIColor colorWithHRed:1.0f Green:1.0f Blue:1.0f alpha:1.0f];
UIColor *colorTwo = [UIColor colorWithHRed:0.0f Green:0.0f Blue:0.0f alpha:1.0f];
NSArray *colors = [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, nil];
grad.colors = colors;
CGRect rect = theCell.backgroundView.bounds;
rect.size.height = rect.size.height / 2;
grad.frame = rect;
[self.layer addsublayer:grad]
You may have to play with the colors a bit, not sure if you had the gradient tilted or not...

iphone sdk- UIGraphics - how to select a superview as current drawing context

i'm trying to draw a line from the originate point of an image view to its destination point.
my problem is (i guess) how to set the superview as current drawing context (from the image view).
can someone help please.
this is the code i'm using in image view..
//UIGraphicsPopContext();
CGContextRef context = UIGraphicsGetCurrentContext(); //(problem here????????)
CGContextSetLineWidth(context, 5.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextMoveToPoint(context, startLocationInView.x, startLocationInView.y);
CGContextAddLineToPoint(context, destinationPositionInView.x, destinationPositionInView.y);
CGContextStrokePath(context);
You cannot draw in other views. What you should do is expand your view's bounds to cover the whole area in which you want to draw.
Alternatively, you could add a new CALayer to your view's layer to cover areas that are outside of your view's bounds.

Am I responsible for clipping when doing custom rendering using drawRect:?

When I call setNeedsDisplayInRect on a UIView, and the drawRect: method fires, am I responsible for making sure I'm not rendering stuff that's outside the CGRect I called, or will the framework handle that for me?
Example:
-(void)drawRect:(CGRect)rect
{
//assume this is called through someMethod below
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor redColor] setFill];
CGContextFillRect(ctx, rect);
[[UIColor blueColor] setFill];
// is this following line a no-op? or should I check to make sure the rect
// I am making is contained within the rect that is passed in?
CGContextFillRect(ctx, CGRectMake(100.0f, 100.0f, 25.0f, 25.0f));
}
-(void)someMethod
{
[self setNeedsDisplayInRect:CGRectMake(50.0f, 50.0f, 25.0f, 25.0f)];
}
To simplify what Barry said: Yes, the framework will handle it for you.
You can safely ignore the rect, anything you draw outside of it will be ignored.
On the other hand, if you draw outside of the rect you are wasting CPU time, so if you can limit your drawing based on the rect, you should.
The framework will clip your drawing. On OS X (AppKit), drawing is clipped to the dirty areas of the NSView (as of 10.3). I'm not sure what the exact clipping algorithm is in UIKit. Of course, you can speed drawing by checking what needs to be drawn and only drawing in the dirty areas of the view, rather than relying on the framework to clip unnecessary drawing.