Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Based on what I found here and over at <a href="https://groups.google.com/forum/?fromgroups=#!topic/cocoa-unbound/Qin6gjYj7XU">https://groups.google.com/forum/?fromgroups=#!topic/cocoa-unbound/Qin6gjYj7XU</a>, I came up with the following which works very well.</p> <pre><code>- (void)drawString:(CFAttributedStringRef)attString inRect:(CGRect)frameRect inContext: (CGContextRef)context { CGContextSaveGState(context); // Flip the coordinate system CGContextSetTextMatrix(context, CGAffineTransformIdentity); CGContextTranslateCTM(context, 0, self.bounds.size.height); CGContextScaleCTM(context, 1.0, -1.0); CGFloat height = self.frame.size.height; frameRect.origin.y = (height - frameRect.origin.y) - frameRect.size.height ; // Create a path to render text in // don't set any line break modes, etc, just let the frame draw as many full lines as will fit CGMutablePathRef framePath = CGPathCreateMutable(); CGPathAddRect(framePath, nil, frameRect); CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attString); CFRange fullStringRange = CFRangeMake(0, CFAttributedStringGetLength(attString)); CTFrameRef aFrame = CTFramesetterCreateFrame(framesetter, fullStringRange, framePath, NULL); CFRelease(framePath); CFArrayRef lines = CTFrameGetLines(aFrame); CFIndex count = CFArrayGetCount(lines); CGPoint *origins = malloc(sizeof(CGPoint)*count); CTFrameGetLineOrigins(aFrame, CFRangeMake(0, count), origins); // note that we only enumerate to count-1 in here-- we draw the last line separately for (CFIndex i = 0; i &lt; count-1; i++) { // draw each line in the correct position as-is CGContextSetTextPosition(context, origins[i].x + frameRect.origin.x, origins[i].y + frameRect.origin.y); CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(lines, i); CTLineDraw(line, context); } // truncate the last line before drawing it if (count) { CGPoint lastOrigin = origins[count-1]; CTLineRef lastLine = CFArrayGetValueAtIndex(lines, count-1); // truncation token is a CTLineRef itself CFRange effectiveRange; CFDictionaryRef stringAttrs = CFAttributedStringGetAttributes(attString, 0, &amp;effectiveRange); CFAttributedStringRef truncationString = CFAttributedStringCreate(NULL, CFSTR("\u2026"), stringAttrs); CTLineRef truncationToken = CTLineCreateWithAttributedString(truncationString); CFRelease(truncationString); // now create the truncated line -- need to grab extra characters from the source string, // or else the system will see the line as already fitting within the given width and // will not truncate it. // range to cover everything from the start of lastLine to the end of the string CFRange rng = CFRangeMake(CTLineGetStringRange(lastLine).location, 0); rng.length = CFAttributedStringGetLength(attString) - rng.location; // substring with that range CFAttributedStringRef longString = CFAttributedStringCreateWithSubstring(NULL, attString, rng); // line for that string CTLineRef longLine = CTLineCreateWithAttributedString(longString); CFRelease(longString); CTLineRef truncated = CTLineCreateTruncatedLine(longLine, frameRect.size.width, kCTLineTruncationEnd, truncationToken); CFRelease(longLine); CFRelease(truncationToken); // if 'truncated' is NULL, then no truncation was required to fit it if (truncated == NULL) truncated = (CTLineRef)CFRetain(lastLine); // draw it at the same offset as the non-truncated version CGContextSetTextPosition(context, lastOrigin.x + frameRect.origin.x, lastOrigin.y + frameRect.origin.y); CTLineDraw(truncated, context); CFRelease(truncated); } free(origins); CGContextRestoreGState(context); </code></pre> <p>}</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload