UIView's drawRect is not getting called - iphone

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}

Related

textview cursor position changed after horizontal line

I want to change the cursor position in TextView...
// NoteView objective _c class its super class is TextView...
#import "NoteView.h"
#implementation NoteView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor =[UIColor whiteColor];
self.contentMode = UIViewContentModeRedraw;
self.font = [UIFont fontWithName:#"Helvetica Neue" size:14];
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
//Get the current drawing context
CGContextRef context = UIGraphicsGetCurrentContext();
//Set the line color and width
// CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.2f].CGColor);
CGContextSetStrokeColorWithColor(context,[UIColor colorWithRed:0.29804f green:0.12157f blue:0.9f alpha:0.1].CGColor);
//Start a new Path
CGContextBeginPath(context);
//Find the number of lines in our textView + add a bit more height to draw lines in the empty part of the view
NSUInteger numberOfLines = (self.contentSize.height + self.bounds.size.height) / self.font.leading;
//Set the line offset from the baseline. (I'm sure there's a concrete way to calculate this.)
CGFloat baselineOffset = 6.0f;
//iterate over numberOfLines and draw each line
for (int x = 0; x < numberOfLines; x++) {
//0.5f offset lines up line with pixel boundary
CGContextMoveToPoint(context, self.bounds.origin.x, self.font.leading*x + 0.5f + baselineOffset);
CGContextAddLineToPoint(context, self.bounds.size.width, self.font.leading*x + 0.5f + baselineOffset);
}
//Close our Path and Stroke (draw) it
CGContextClosePath(context);
CGContextStrokePath(context);
}
//its a view controller class and here i imported NotesView here
#import "NotesViewController.h"
#interface NotesViewController ()
#end
#implementation NotesViewController
// i load the textView frame whatever i created class above
- (void)loadView {
[super loadView];
CGSize result = [[UIScreen mainScreen] bounds].size;
CGFloat scale = [UIScreen mainScreen].scale;
result = CGSizeMake(result.width*scale, result.height * scale);
if (result.height==1136)
{
_TextView = [[NoteView alloc] initWithFrame:CGRectMake(29,50,266,430)];
backgroundView.frame=CGRectMake(10,32,300,450);
}
else
{
_TextView = [[NoteView alloc] initWithFrame:CGRectMake(29,50,266,340)];
backgroundView.frame=CGRectMake(10,32,300,360);
}
[self.view addSubview:_TextView];
_TextView.delegate = self;
UIView *lineView = [[UIView alloc]initWithFrame:CGRectMake(30,40,1,backgroundView.frame.size.height-5)];
lineView.backgroundColor = [UIColor brownColor];
lineView.alpha=0.3;
[self.view addSubview:lineView];
UIView *lineView1 = [[UIView alloc]initWithFrame:CGRectMake(32,40,1,backgroundView.frame.size.height-5)];
lineView1.backgroundColor = [UIColor brownColor];
lineView1.alpha=0.3;
[self.view addSubview:lineView1];
}
}
}
// in view did load i set the delegate and code for cursor position
- (void)viewDidLoad
{
[super viewDidLoad];
// setting delegate here
_TextView.delegate=self;
_TextView.editable = YES;
[_TextView setSelectedRange:NSMakeRange(10, 0)];
}
I write all the delegate methods for Textview and ScrollView of Textview I the cursor positon is starts the vertical line after.... I'm not expressed well please understand based on images... I want cursor position... I want to set my Textview with real note application in iPhone.. I add Textview to ViewController all works well but cursor stats starting position... I want to cursor position always horizontal line........ Try to give solution based on the images..
Do it like this image.
Here you have to set the position of your textview in your VC so it will come after the horizontal line.

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.

CGContextDrawPDFPage is drawing the page on the wrong origin point

Edit: It seems that the origin point's components are been multiplied by 2 when drawing the PDF page. Is something I'm doing causing this?
I have a UIViewController that displays a PDF page on a UIScrollView. the PDF page itself is drawn on a CATiledLayer, however, when my view controller draws the layer there is a considerable offset between the layer's bounds and the drawn PDF. As you can see in the picture, the page should have been drawn on the yellow view:
Here is the relevant code that draws the page:
- (void)refreshPage
{
if(contentView) {
for(UIView *v in self.view.subviews) {
[v removeFromSuperview];
[v release];
}
}
CGRect pageRect = CGRectIntegral(CGPDFPageGetBoxRect(self._document.page, kCGPDFCropBox));
pageRect.origin.x = ((self.view.frame.size.width / 2) - (pageRect.size.width / 2));
CATiledLayer *tiledLayer = [CATiledLayer layer];
tiledLayer.delegate = self;
tiledLayer.tileSize = CGSizeMake(1024.0, 1024.0);
tiledLayer.levelsOfDetail = 1000;
tiledLayer.levelsOfDetailBias = 1000;
tiledLayer.frame = pageRect;
contentView = [[UIView alloc] initWithFrame:pageRect];
[contentView.layer addSublayer:tiledLayer];
CGRect viewFrame = self.view.frame;
viewFrame.origin = CGPointZero;
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:viewFrame];
//[scrollView setBackgroundColor:[UIColor cyanColor]];
//[contentView setBackgroundColor:[UIColor yellowColor]];
scrollView.delegate = self;
scrollView.contentSize = pageRect.size;
scrollView.maximumZoomScale = 1000;
[scrollView addSubview:contentView];
[self.view addSubview:scrollView];
pagingViewController = [[PDFPagingViewController alloc] initWithDocument:self._document AndObserver:self];
[self.view addSubview:pagingViewController.view];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return contentView;
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
if(self._document) {
[layer setBackgroundColor:(CGColorRef)[UIColor redColor]];
CGRect drawingRect = CGContextGetClipBoundingBox(ctx);
CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(ctx, drawingRect);
CGContextTranslateCTM(ctx, 0.0, layer.bounds.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextConcatCTM(ctx, CGPDFPageGetDrawingTransform(self._document.page, kCGPDFCropBox, layer.bounds, 0, true));
CGContextDrawPDFPage(ctx, self._document.page);
}
}
You need to change when you set the pageRect's origin (which I assume you do to center in the view). You are setting both the layer's frame and the contentView's frame to the offset pageRect when you really intend to offset only one.
-(void)refreshPage {
//...
CGRect pageRect = CGRectIntegral(CGPDFPageGetBoxRect(self._document.page, kCGPDFCropBox));
CATiledLayer *tiledLayer = [CATiledLayer layer];
//...
tiledLayer.frame = pageRect;
// set the pageRect origin now to center the contentView, not the layer
pageRect.origin.x = ((self.view.frame.size.width / 2) - (pageRect.size.width / 2));
contentView = [[UIView alloc] initWithFrame:pageRect];
[contentView.layer addSublayer:tiledLayer];
//...
}

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.

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];