2013-02-23 5 views
6

J'ai le code suivant, que j'essaye de dessiner en utilisant le texte de base et c'est pourquoi je ne peux pas découper le texte comme UILabel. en d'autres termes je dois comprendre l'ellipse ('...') mon moi. Je rencontre des difficultés à trouver la plage de '...' basée sur un CGSize. Quel serait le meilleur moyen de comprendre cela?Ajouter des ellipses à NSString

Voilà comment je dessine ce:

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

la 'NSString Peut-on utiliser drawAtPoint: forWidth: withFont: lineBreakMode: méthode (ou similaire) passant NSLineBreakByTruncatingTail comme mode de saut de ligne? – rmaddy

+0

@rmaddy J'ai édité le post ci-dessus pour montrer comment je dessine le texte. Je n'utilise en fait pas drawAtPoint – adit

+0

Je suis assez sûr qu'il y a une facilité pour faire des ellipses automatiquement, bien que je ne puisse pas le trouver maintenant. (Pensait peut-être NSFont, mais je ne le vois pas là.) –

Répondre

5

EDIT

(Ma réponse originale ici n'a pas été utile, elle ne prenait pas plusieurs lignes Si quelqu'un veut le voir pour des raisons historiques. l'intérêt, regardez dans l'historique d'édition, je l'ai supprimé car il cause plus de confusion qu'il ne résout.La réponse actuelle est le code correct.)

Ce que vous devez faire est laisser CTFramesetter travailler toutes les lignes excep t le dernier. Ensuite, vous pouvez tronquer le dernier à la main si nécessaire.

- (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

Je ne vois aucun NSLineBreakMode dans cet exemple – adit

+0

Je suis en train d'appeler CFRelease à la fin, je le montre juste ici – adit

+0

Oui, mais 'kCTParagraphStyleSpecifierAlignment' est dans l'exemple, et le retour à la ligne est fondamentalement le même. –

1

Que diriez-vous quelque chose comme ça ...

- (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

La façon la plus facile et plus simple,

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

pour more

Questions connexes