6 votes

ajout de points de suspension à NSString

J'ai le code suivant, que j'essaie de dessiner en utilisant du texte de base et c'est pourquoi je ne peux pas couper le texte comme le fait UILabel. En d'autres termes, je dois trouver moi-même les points de suspension ('...').

 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:@"..."];
        }

J'ai du mal à trouver l'intervalle dans lequel le "..." est basé sur un CGSize. Quelle serait la meilleure façon de le faire ?

Voici comment je le dessine :

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

5voto

Rob Napier Points 92148

EDIT

(Ma réponse originale ici n'était pas utile ; elle ne gérait pas les lignes multiples. Si quelqu'un veut la voir pour son intérêt historique, regardez dans l'historique des modifications. Je l'ai supprimée car elle cause plus de confusion qu'elle n'en résout. La réponse actuelle est un code correct).

Ce que vous devez faire, c'est laisser CTFramesetter travaillez sur toutes les lignes sauf la dernière. Vous pouvez ensuite tronquer la dernière ligne à 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);
}

1voto

danh Points 21498

Que diriez-vous de 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;
}

0voto

damithH Points 956

Le moyen le plus facile et le 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]];

para plus

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X