Quartz 2d trying to redraw a triangle - iphone

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.

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}

How to let drawRect get the value of points from ViewController and draw?

I created a class newView from UIView and aim to draw a quadrangle. the 4 coners (ClipPointA, ClipPointB, ClipPointC, ClipPointD) of the quadrangle are supposed to read value from ViewController.
newView.h:
#interface newView : UIView {
CGPoint ClipPointA, ClipPointB, ClipPointC, ClipPointD;
}
#end
newView.m:
#implementation newView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 0.0, 1.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, ClipPointA.x, ClipPointA.y); //start point
CGContextAddLineToPoint(context, ClipPointB.x, ClipPointB.y);
CGContextAddLineToPoint(context, ClipPointD.x, ClipPointD.y);
CGContextAddLineToPoint(context, ClipPointC.x, ClipPointC.y); // end path
CGContextClosePath(context); // close path
CGContextSetLineWidth(context, 2.0);
CGContextStrokePath(context);
}
- (void)dealloc {
[super dealloc];
}
#end
I created the instance of newView in ViewController.
How do I write next part of code to let 4 CGPoints read value from ViewController?
Thanks.
when you create the new UIView please pass the points also for eg:let A,B,C,D be your 4 points
newView *nv =[[dragman alloc]initWithFrame:self.view.frame];
nv.ClipPointA=A;
nv.ClipPointB=B;
nv.ClipPointC=C;
nv.ClipPointD=D;
[nv setUserInteractionEnabled:YES];
[contentView addSubview:nv];
[nv release];

drawRect is not working In Iphone

Hi i m adding UIView to window.
this view has drawRect as-
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, 300, 400);
CGContextStrokePath(context);
}
but this code is not drawing any line.
so any help for this??????
use
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);
after your code.
I think Marcelo Cantos is right. You should set stroke color.
Maybe you can try this to set color.
[[UIColor blackColor] set];

Making a layer structure for a drawing application

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