secret
Last active

Line numbers implementation for UITextView

  • Download Gist
LineNumbersView.m
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
//
// LineNumbersView.m
// ATTest
//
// Created by Amar Kulo on 2012-10-06.
// Copyright (c) 2012 Amar Kulo. All rights reserved.
//
 
#define DebugLines 0
#define LineHeight 22
#define LeftMargin 8.5
#define RightMargin 15
 
#define FontName @"SourceCodePro-Regular"
#define FontSize 14
#define Font [UIFont fontWithName:FontName size:FontSize]
 
#import "LineNumbersView.h"
#import <tgmath.h>
 
static CGFloat TOPMARGIN = 8;
 
@interface LineNumbersView ()
 
@end
 
@implementation LineNumbersView
@synthesize text;
@synthesize showLineNumbers;
@synthesize editorWidth;
@synthesize contentOffset;
 
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor colorWithRed:0.945 green:0.945 blue:0.945 alpha:1.000]];
[self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
}
return self;
}
 
- (void)drawRect:(CGRect)rect
{
if (showLineNumbers) {
// Draw separator line
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(self.frame.size.width, 0)];
[bezierPath addLineToPoint: CGPointMake(self.frame.size.width, self.frame.size.height)];
[[UIColor colorWithRed:0.573 green:0.573 blue:0.573 alpha:1.000] setStroke];
bezierPath.lineWidth = 0.5;
[bezierPath stroke];
// create context for drawing
CGContextRef context = UIGraphicsGetCurrentContext();
// get array of all lines in editor
NSArray *allLinesInEditor = [text componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
// test string for determining actual size of font used
NSString *testLine = @" ";
// calculate size of the string
CGSize testLineSize = [testLine sizeWithFont:[UIFont systemFontOfSize:14]];
// calculate maxWidth of the target frame
CGFloat maxWidth = editorWidth - LeftMargin - RightMargin;
if (DebugLines) {
NSLog(@"Test line size: %@", NSStringFromCGSize(testLineSize));
NSLog(@"Max width: %f", maxWidth);
}
int lastLineLocation = 0;
for (int i = 0; i < allLinesInEditor.count; i++) {
// retrieve line from array
NSString *line = [allLinesInEditor objectAtIndex:i];
// tab substituion
NSString *newLine = [line stringByReplacingOccurrencesOfString:@"\t" withString:@" "];
// calculate line size
CGSize lineSizeFromUIKit = [newLine sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(maxWidth, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
// storage for line CGRect
CGRect lineRect;
// storage for calculated line height
CGFloat lineHeight = lineSizeFromUIKit.height;
if (i == 0) {
// create rect for first line
lineRect = CGRectMake(0, TOPMARGIN, self.bounds.size.width - 4, 15.084);
} else {
// create rect for new line
lineRect = CGRectMake(0, lastLineLocation, self.bounds.size.width - 4, 15.084);
}
if (line.length == 0) { // empty or new line
// add values to lastLineLocation
lastLineLocation = lineRect.origin.y + testLineSize.height;
} else { // regular line
if (fmod(lineHeight, testLineSize.height) > 0) { // check if there is reminder for line
// calculate number of lines as integer without remainder
int numberOfLines = lineHeight / testLineSize.height;
// then add one line which represents remainder, to number of lines and multiply with line height
lineHeight = (numberOfLines + 1) * testLineSize.height;
}
// add values to lastLineLocation
lastLineLocation = lineRect.origin.y + lineHeight;
}
// substract valule of content offset of editor view
lineRect.origin.y -= contentOffset.y;
if (DebugLines) {
NSLog(@"------------------------------------------------------------------------------------------");
//const char *cString = [line UTF8String];
NSLog(@"Line %i: %@ length: %i", i+1, line.description, line.length);
NSLog(@"Line %i: %@ new line length: %i", i+1, newLine.description, newLine.length);
//NSLog(@"Line %i: %@ char representation: %s", i+1, line, cString);
NSLog(@"Line %i: sizeFromUIKit: %@", i+1, NSStringFromCGSize(lineSizeFromUIKit));
//NSLog(@"Line %i: sizeFromCText: %@", i+1, NSStringFromCGSize(lineSizeFromCoreText));
//NSLog(@"Line %i: sizeFromCharNr: %@", i+1, NSStringFromCGSize(CGSizeMake((line.length * testLineSize.width) / maxWidth, CGFLOAT_MAX)));
NSLog(@"Line %i: number of lines: %f", i+1, lineHeight / testLineSize.height);
NSLog(@"Line %i: new last line location - %d", i+1, lastLineLocation);
}
// drawing
// line background color
CGContextSetFillColorWithColor(context,[UIColor colorWithRed:0.573 green:0.573 blue:0.573 alpha:1.000].CGColor);
// draw line number
[[NSString stringWithFormat:@"%i", i+1] drawInRect:lineRect withFont:[UIFont systemFontOfSize:14] lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentRight];
}
}
}
 
@end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.