2010-05-14 25 views

Antwort

9

ich erreichte dies durch UIView und Überschreiben der drawRect: Methode, wie so Subklassen:

#define TXT_VIEW_INSETS 8.0 // The default insets for a UITextView is 8.0 on all sides 

@implementation NumberedTextView 

@synthesize lineNumbers; 
@synthesize delegate; 

- (id)initWithFrame:(CGRect)frame { 
    if ((self = [super initWithFrame:frame])) { 
     [self setContentMode:UIViewContentModeRedraw]; 

     internalScrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; 
     [internalScrollView  setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 
     [internalScrollView  setBackgroundColor:[UIColor clearColor]]; 
     [internalScrollView   setClipsToBounds:YES]; 
     [internalScrollView   setScrollsToTop:YES]; 
     [internalScrollView   setContentSize:self.bounds.size]; 
     [internalScrollView   setContentMode:UIViewContentModeLeft]; 
     [internalScrollView    setDelegate:self]; 
     [internalScrollView    setBounces:NO]; 

     internalTextView = [[UITextView alloc] initWithFrame:self.bounds]; 
     [internalTextView setAutocapitalizationType:UITextAutocapitalizationTypeNone]; 
     [internalTextView  setAutocorrectionType:UITextAutocorrectionTypeNo]; 
     [internalTextView  setSpellCheckingType:UITextSpellCheckingTypeNo]; 
     [internalTextView  setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 
     [internalTextView   setBackgroundColor:[UIColor clearColor]]; 
     [internalTextView   setClipsToBounds:YES]; 
     [internalTextView   setScrollsToTop:NO]; 
     [internalTextView    setContentMode:UIViewContentModeLeft]; 
     [internalTextView    setDelegate:self]; 
     [internalTextView     setBounces:NO]; 

     [internalScrollView addSubview:internalTextView]; 
     [self addSubview:internalScrollView]; 
    } 
    return self; 
} 

- (void)drawRect:(CGRect)rect { 
    if (self.lineNumbers) { 
     [[internalTextView textColor] set]; 
     CGFloat xOrigin, yOrigin, width/*, height*/; 
     uint numberOfLines = (internalTextView.contentSize.height + internalScrollView.contentSize.height)/internalTextView.font.lineHeight; 
     for (uint x = 0; x < numberOfLines; ++x) { 
      NSString *lineNum = [NSString stringWithFormat:@"%d:", x]; 

      xOrigin = CGRectGetMinX(self.bounds); 

      yOrigin = ((internalTextView.font.pointSize + abs(internalTextView.font.descender)) * x) + TXT_VIEW_INSETS - internalScrollView.contentOffset.y; 

      width = [lineNum sizeWithFont:internalTextView.font].width; 
//   height = internalTextView.font.lineHeight; 

      [lineNum drawAtPoint:CGPointMake(xOrigin, yOrigin) withFont:internalTextView.font]; 
     } 

     CGRect tvFrame = [internalTextView frame]; 
     tvFrame.size.width = CGRectGetWidth(internalScrollView.bounds) - width; 
     tvFrame.size.height = MAX(internalTextView.contentSize.height, CGRectGetHeight(internalScrollView.bounds)); 
     tvFrame.origin.x = width; 
     [internalTextView setFrame:tvFrame]; 
     tvFrame.size.height -= TXT_VIEW_INSETS; // This fixed a weird content size problem that I've forgotten the specifics of. 
     [internalScrollView setContentSize:tvFrame.size]; 
    } 
} 

#pragma mark - UITextView Delegate 

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { 
    [self setNeedsDisplay]; 
    return YES; 
} 

- (void)textViewDidChange:(UITextView *)textView { 
    [self setNeedsDisplay]; 
} 

- (void)textViewDidChangeSelection:(UITextView *)textView { 
    [self setNeedsDisplay]; 
} 

#pragma mark - UIScrollView Delegate 

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { 
    [self setNeedsDisplay]; 
} 
+0

Vielen Dank für die Freigabe des Codes. Zu guter Letzt: Für andere Leute, die das ausprobiert haben, wird die Zeilenumbruch nicht berücksichtigt, und die Zeilennummern sind nur eine visuelle Zählung der Zeilen, keine tatsächlichen Zeilen im Text. – Philosophistry

+0

@Philosophphystry Danke, dass Sie dies hervorgehoben haben; Ich habe vergessen, das zu erwähnen. Dieser Code behandelt Zeilenumbruch nicht, da ich in der Methode 'layoutSubviews' sicherstelle, dass' internalScrollView' und 'internalTextView' beide breit genug sind, um die längste Textzeile ohne Umbruch zu verarbeiten (ich passe die Rahmenbreite bei' internalTextView' an) Textinhalt ändert sich, aber "layoutSubviews" überprüft doppelt, um sicherzustellen, dass sie tatsächlich breit genug sind. Dies war beabsichtigt, weil der Versuch, die Zeilennummerierung mit dem Wrapping arbeiten zu lassen, ein großer Kopfschmerz gewesen wäre. – chown

+0

Ich habe ein merkwürdiges Problem: wie ich presse return auf der uitextview, gibt es eine große Lücke zwischen der Zeilennummer und der Position des Cursors/Caret mit identischem Code wie hier gesagt. Irgendwelche Ideen? Vielen Dank –

-2

Es gibt nichts eingebaut dafür. Du musst es selbst tun.

+8

Es könnte einfacher sein, UITextView Unterklasse und die Zeichenmethoden dort zu bearbeiten, obwohl es wahrscheinlich eine lästige Pflicht aus jedem Winkel sein wird. – JoePasq

Verwandte Themen