Bob Ashmore
Bob Ashmore

Reputation: 91

Drawing ruled lines on a UITextView for IPhone

I would like to create a view like the notes app on iPhone and therefor need the view to have ruled lines as per the notes app, I have done this in windows where you need to get the font metrics and then draw the lines onto the device context, has anyone done this in the UITextView if so some help would be appriciated

Upvotes: 4

Views: 6448

Answers (4)

Dave Batton
Dave Batton

Reputation: 8835

Subclass UITextView. Override -drawRect:

- (void)drawRect:(CGRect)rect
{    
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
    CGContextSetLineWidth(context, self.lineWidth);
    CGFloat strokeOffset = (self.lineWidth / 2);

    CGFloat rowHeight = self.font.lineHeight;
    if (rowHeight > 0) {
        CGRect rowRect = CGRectMake(self.contentOffset.x, - self.bounds.size.height, self.contentSize.width, rowHeight);
        while (rowRect.origin.y < (self.bounds.size.height + self.contentSize.height)) {
            CGContextMoveToPoint(context, rowRect.origin.x + strokeOffset, rowRect.origin.y + strokeOffset);
            CGContextAddLineToPoint(context, rowRect.origin.x + rowRect.size.width + strokeOffset, rowRect.origin.y + strokeOffset);
            CGContextDrawPath(context, kCGPathStroke);
            rowRect.origin.y += rowHeight;
        }
    }
}

When you init the text view, be sure to set the contentMode to UIViewContentModeRedraw. Otherwise the lines won't scroll with the text.

self.contentMode = UIViewContentModeRedraw;

This isn't perfect. Ideally you should just draw into the rect that's passed. But I was lazy and this worked for my needs.

Upvotes: 8

Bob Ashmore
Bob Ashmore

Reputation: 91

I think this works OK but I feel it has been hacked and I do not fully undestand the mechanism of the UITextView class;

first you must add the following to your delegate to force a redraw on scrolling

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{   
    // NSLog(@"scrollViewDidScroll The scroll offset is ---%f",scrollView.contentOffset.y);
    [noteText setNeedsDisplay];
}

then implement drawRect in the subclass as so

- (void)drawRect:(CGRect)rect {
    // Drawing code
    // Get the graphics context
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    [super drawRect:rect];

    // Get the height of a single text line
    NSString *alpha = @"ABCD";
    CGSize textSize = [alpha sizeWithFont:self.font constrainedToSize:self.contentSize lineBreakMode:UILineBreakModeWordWrap];
    NSUInteger height = textSize.height;

    // Get the height of the view or contents of the view whichever is bigger
    textSize = [self.text sizeWithFont:self.font constrainedToSize:self.contentSize lineBreakMode:UILineBreakModeWordWrap];
    NSUInteger contentHeight = (rect.size.height > textSize.height) ? (NSUInteger)rect.size.height : textSize.height;

    NSUInteger offset = 6 + height; // MAGIC Number 6 to offset from 0 to get first line OK ???
    contentHeight += offset;
    // Draw ruled lines
    CGContextSetRGBStrokeColor(ctx, .8, .8, .8, 1);
    for(int i=offset;i < contentHeight;i+=height) {
        CGPoint lpoints[2] = { CGPointMake(0, i), CGPointMake(rect.size.width, i) };
        CGContextStrokeLineSegments(ctx, lpoints, 2);
    }
}

Still worry about this Magic Number 6

Bob

Upvotes: 5

ThE uSeFuL
ThE uSeFuL

Reputation: 1534

@lukya, Your solution is bit messy as when we scroll the UITextView the text only scrolls leaving the lines (coming from the image) in its place.

A better solution would be to add subview to your text view where you have drawn the lines. You need to add an observer to the text view in order to track its change in content size as the text increase/decrease.

Upvotes: 0

Swapnil Luktuke
Swapnil Luktuke

Reputation: 10475

You can try setting the backgroundColor of you textView using an image with ruled lines

textView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"RuledLinesPage.png"]];

Color with pattern image creates a tiled image if the area to be filled with the color is larger than the image. So you will have to make sure that the image size is correct size/tileable (I don't think 'tileable' is a real word but i hope you get what i mean). Also you will have to create the image with ruled lines to best match you textView's font.

Good Luck.

Upvotes: 1

Related Questions