2013-02-23 11 views
6

Mam następujący kod, który próbuję narysować za pomocą tekstu podstawowego i dlatego nie mogę przypiąć tekstu, jak to, co robi UILabel. innymi słowy muszę wymyślić elipsę ("...") siebie.Dodawanie wielokropka do NSString

CGSize commentSize = [[self.sizeDictionary_ valueForKey:commentSizeKey] CGSizeValue]; 
     CGSize actualSize = [[self.sizeDictionary_ valueForKey:actualCommentSizeKey] CGSizeValue]; 

NSString *actualComment = self.highlightItem_.comment; 
     if (actualSize.height > commentSize.height){ 
      actualComment = [self.highlightItem_.comment stringByReplacingCharactersInRange:NSMakeRange(68, 3) withString:@"..."]; 
     } 

Mam trudny czas na znalezienie zakresu, w którym "..." na podstawie CGSize. Jaki byłby najlepszy sposób, by to rozgryźć?

Oto jak mam go rysunek:

CFStringRef string = CFBridgingRetain(actualComment); 
     CFMutableAttributedStringRef comment = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0); 
     CFAttributedStringReplaceString (comment ,CFRangeMake(0, 0), string); 

     CGColorRef blue = CGColorRetain([UIColor colorWithRed:131/255.f green:204/255.f blue:253/255.f alpha:1.0].CGColor); 
     CGColorRef gray = CGColorRetain([UIColor colorWithWhite:165/255.f alpha:1.0].CGColor); 

     CFAttributedStringSetAttribute(comment, CFRangeMake(0, [name length]),kCTForegroundColorAttributeName, blue); 
     CFAttributedStringSetAttribute(comment, CFRangeMake([name length], [self.highlightItem_.comment length] - [name length]),kCTForegroundColorAttributeName, gray); 

     CGColorRelease (blue); 
     CGColorRelease (gray); 

     CTFontRef nameFont = CTFontCreateWithName(CFBridgingRetain(kProximaNovaBold), 13.0f, nil); 
     CFAttributedStringSetAttribute(comment,CFRangeMake(0, [name length]),kCTFontAttributeName,nameFont); 

     CTFontRef commentFont = CTFontCreateWithName(CFBridgingRetain(kProximaNovaRegular), 13.0f, nil); 
     CFAttributedStringSetAttribute(comment, CFRangeMake([name length], [self.highlightItem_.comment length] - [name length]),kCTFontAttributeName,commentFont); 

     CGFloat commentYOffset = floorf((self.commentHeight_ - commentSize.height)/2); 

     CGContextSaveGState(context); 
     CGRect captionFrame = CGRectMake(0, 0, rect.size.width - 80, commentSize.height); 
     CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(comment); 
     CGMutablePathRef captionFramePath = CGPathCreateMutable(); 
     CGPathAddRect(captionFramePath, NULL, captionFrame); 

     CTFrameRef mainCaptionFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), captionFramePath, NULL); 

     CGContextRef context = UIGraphicsGetCurrentContext(); 
     CGContextSetTextMatrix(context, CGAffineTransformIdentity); 
     CGContextTranslateCTM(context, self.buttonSize_ + 25, self.imageHeight_ + self.commentHeight_ + 6 - commentYOffset); 
     CGContextScaleCTM(context, 1.0, -1.0); 

     CTFrameDraw(mainCaptionFrame, context); 
     CGContextRestoreGState(context); 
+0

można użyć 'NSString drawAtPoint: forWidth: withFont: lineBreakMode: '(lub podobna) metoda przekazująca' NSLineBreakByTruncatingTail' jako tryb przełamania linii? – rmaddy

+0

@rmaddy Edytowałem powyższy wpis, aby pokazać, jak rysuję tekst. W rzeczywistości nie używam drawAtPoint – adit

+0

Jestem prawie pewny, że jest automat do wykonywania elips automatycznie, choć nie mogę go teraz znaleźć. (Myślał może NSFont, ale go tam nie widzę.) –

Odpowiedz

5

EDIT

(mój oryginalny odpowiedź tutaj nie był przydatny, ale nie obsługiwać wiele linii Jeśli ktoś chce zobaczyć na historyczny. zainteresowanie, patrzeć w historii edycji. Usunąłem go, ponieważ powoduje to więcej zamieszania niż rozwiązuje. aktualna odpowiedź jest poprawna kod.)

Co trzeba zrobić, to niech CTFramesetter pracy wszystkie linie excep t ostatni. Następnie możesz skrócić ostatnią ręcznie, jeśli to konieczne.

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

    CGRect pathRect = CGRectMake(50, 200, 200, 40); 
    CGPathRef path = CGPathCreateWithRect(pathRect, NULL); 

    CFAttributedStringRef attrString = (__bridge CFTypeRef)[self attributedString]; 

    // Create the framesetter using the attributed string 
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString); 

    // Create a single frame using the entire string (CFRange(0,0)) 
    // that fits inside of path. 
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); 

    // Draw the lines except the last one 
    CFArrayRef lines = CTFrameGetLines(frame); 
    CFIndex lineCount = CFArrayGetCount(lines); 
    CGPoint origins[lineCount]; // I'm assuming that a stack variable is safe here. 
           // This would be bad if there were thousdands of lines, but that's unlikely. 
    CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); 
    for (CFIndex i = 0; i < lineCount - 1; ++i) { 
    CGContextSetTextPosition(context, pathRect.origin.x + origins[i].x, pathRect.origin.y + origins[i].y); 
    CTLineDraw(CFArrayGetValueAtIndex(lines, i), context); 
    } 

    /// 
    /// HERE'S THE INTERESTING PART 
    /// 
    // Make a new last line that includes the rest of the string. 
    // The last line is already truncated (just with no truncation mark), so we can't truncate it again 
    CTLineRef lastLine = CFArrayGetValueAtIndex(lines, lineCount - 1); 
    CFIndex lastLocation = CTLineGetStringRange(lastLine).location; 
    CFRange restRange = CFRangeMake(lastLocation, CFAttributedStringGetLength(attrString) - lastLocation); 
    CFAttributedStringRef restOfString = CFAttributedStringCreateWithSubstring(NULL, attrString, restRange); 
    CTLineRef restLine = CTLineCreateWithAttributedString(restOfString); 


    // We need to provide the truncation mark. This is an ellipsis (Cmd-semicolon). 
    // You could also use "\u2026". Don't use dot-dot-dot. It'll work, it's just not correct. 
    // Obviously you could cache this… 
    CTLineRef ellipsis = CTLineCreateWithAttributedString((__bridge CFTypeRef) 
                 [[NSAttributedString alloc] initWithString:@"…"]); 

    // OK, now let's truncate it and draw it. I'm being a little sloppy here. If ellipsis could possibly 
    // be wider than the path width, then this will fail and truncateLine will be NULL and we'll crash. 
    // Don't do that. 
    CTLineRef truncatedLine = CTLineCreateTruncatedLine(restLine, 
                 CGRectGetWidth(pathRect), 
                 kCTLineTruncationEnd, 
                 ellipsis); 
    CGContextSetTextPosition(context, pathRect.origin.x + origins[lineCount - 1].x, pathRect.origin.y + origins[lineCount - 1].y); 
    CTLineDraw(truncatedLine, context); 

    CFRelease(truncatedLine); 
    CFRelease(ellipsis); 
    CFRelease(restLine); 
    CFRelease(restOfString); 
    CFRelease(frame); 
    CFRelease(framesetter); 
    CGPathRelease(path); 
} 
+0

Nie widzę żadnego NSLineBreakMode w tym przykładzie – adit

+0

Właściwie wywołuję CFRelease na końcu, właśnie pokazuję go tutaj – adit

+0

Tak, ale "kCTParagraphStyleSpecifierAlignment" jest w przykładzie, a podział wiersza jest w zasadzie taki sam. –

1

Jak o czymś takim ...

- (NSString *)truncate:(NSString *)string toWidth:(CGFloat)width withFont:(UIFont *)font { 

    CGSize size = [string sizeWithFont:font]; 
    if (size.width <= width) return string; 

    NSString *truncatedString = [string copy]; 
    NSString *ellipticalString = [truncatedString stringByAppendingString:@"..."]; 
    size = [ellipticalString sizeWithFont:font]; 

    while (size.width > width && truncatedString.length) { 
     truncatedString = [truncatedString substringToIndex:(truncatedString.length-1)]; 
     ellipticalString = [truncatedString stringByAppendingString:@"..."]; 
     size = [ellipticalString sizeWithFont:font]; 
    } 
    return ellipticalString; 
} 
0

najłatwiejszy i najprostszy sposób,

NSString *theText = @"bla blah bla bhla bla bla"; 
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; 
[style setLineBreakMode:NSLineBreakByTruncatingTail]; 
[theText drawInRect:dirtyRect withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:style, NSParagraphStyleAttributeName,nil]]; 

dla more