2013-02-23 106 views
6

我有以下代碼,我正在嘗試使用核心文本進行繪製,這就是爲什麼我無法剪輯像UILabel所做的那樣的文本。換句話說,我必須找出省略號('...')我的自我。向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:@"..."]; 
     } 

我很難找到基於CGSize的'...'的範圍。解決這個問題最好的方法是什麼?

以下是我正在繪製它:

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

你能使用'的NSString drawAtPoint:forWidth: withFont:lineBreakMode:傳遞'NSLineBreakByTruncatingTail'作爲換行符模式的'(或類似的)方法? – rmaddy 2013-02-23 17:35:32

+0

@rmaddy我編輯了上面的帖子來展示我如何繪製文本。我實際上沒有使用drawAtPoint – adit 2013-02-23 17:43:00

+0

我很確定有一個工具可以自動執行省略號,儘管我現在找不到它。 (想着也許NSFont,但我沒有看到它。) – 2013-02-23 19:01:01

回答

5

編輯

(我這裏原來的答案是沒有用的,它不處理多條線路如果有人想看到它的歷史。感興趣,查看編輯歷史記錄,我刪除了它,因爲它導致了更多的困惑,而不是解決問題的答案。)

你需要做的就是讓CTFramesetter解決所有的問題excep最後一個。然後,如果需要,您可以手動截斷最後一個。

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

我在該例中沒有看到任何NSLineBreakMode – adit 2013-02-24 01:01:32

+0

我實際上在最後調用CFRelease,現在我只是在這裏顯示它 – adit 2013-02-24 01:03:27

+0

是的,但'kCTParagraphStyleSpecifierAlignment'在示例中,換行符基本相同。 – 2013-02-24 01:46:23

1

如何這樣的事情...

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

最簡單,最簡單的方法,

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

more