【问题标题】:Vertical align with Core Text?与核心文本垂直对齐?
【发布时间】:2011-03-18 02:14:30
【问题描述】:

如何更改 CTFramesetter 框架中文本的垂直对齐方式?我希望我的文本位于中间而不是位于 顶部。我正在使用核心文本框架。有一个段落的设置可以改变水平对齐而不是垂直。

【问题讨论】:

    标签: alignment core-text


    【解决方案1】:

    终于想通了……

    CGRect boundingBox = CTFontGetBoundingBox(font);
    
    //Get the position on the y axis
    float midHeight = self.frame.size.height / 2;
    midHeight -= boundingBox.size.height / 2;
    
    CGPathAddRect(path, NULL, CGRectMake(0, midHeight, self.frame.size.width, boundingBox.size.height));
    

    【讨论】:

    • 这不适用于某些字体。刚用 AcademyEngravedLetPlain 字体测试过,字体没有画出来
    • 但我设法通过将矩形大小高度设置为原始边界高度而不是边界框高度来解决这个问题
    • 可以使用CTFramesetterSuggestFrameSizeWithConstraints返回的大小来计算midHeight,支持多行。
    【解决方案2】:

    感谢尼克,这是一个很棒的 sn-p。

    只是在此基础上进行扩展,如果您使用枚举进行顶部、中间和底部对齐,例如,您可以这样做:

    if (VerticalAlignmentTop == currentTextAlignment) {
        CGPathAddRect(path, NULL, rect); // Draw normally (top)
    }
    else if (VerticalAlignmentMiddle == currentTextAlignment) {
        CGRect boundingBox = CTFontGetBoundingBox(fontRef);
    
        //Get the position on the y axis (middle)
        float midHeight = rect.size.height / 2;
        midHeight -= boundingBox.size.height / 2;
    
        CGPathAddRect(path, NULL, CGRectMake(0, midHeight, rect.size.width, boundingBox.size.height));  
    }
    else {
        CGRect boundingBox = CTFontGetBoundingBox(fontRef);
    
        CGPathAddRect(path, NULL, CGRectMake(0, 0, rect.size.width, boundingBox.size.height));  
    }
    

    【讨论】:

      【解决方案3】:

      这说明了一个框架中可以使用多种字体类型和样式(计算文本的高度和宽度,查看if(index == lastLineIndex) 块以查看计算高度的位置):

      - (CGSize) measureFrame: (CTFrameRef) frame forContext: (CGContext *) cgContext
      {
          CGPathRef framePath = CTFrameGetPath(frame);
          CGRect frameRect = CGPathGetBoundingBox(framePath);
      
          CFArrayRef lines = CTFrameGetLines(frame);
          CFIndex numLines = CFArrayGetCount(lines);
      
          CGFloat maxWidth = 0;
          CGFloat textHeight = 0;
      
          // Now run through each line determining the maximum width of all the lines.
          // We special case the last line of text. While we've got it's descent handy,
          // we'll use it to calculate the typographic height of the text as well.
      
          CFIndex lastLineIndex = numLines - 1;
          for(CFIndex index = 0; index < numLines; index++)
          {
              CGFloat ascent, descent, leading, width;
              CTLineRef line = (CTLineRef) CFArrayGetValueAtIndex(lines, index);
              width = CTLineGetTypographicBounds(line, &ascent,  &descent, &leading);
      
              if(width > maxWidth)
              {
                  maxWidth = width;
              }
      
              if(index == lastLineIndex)
              {
                  // Get the origin of the last line. We add the descent to this
                  // (below) to get the bottom edge of the last line of text.
      
                  CGPoint lastLineOrigin;
                  CTFrameGetLineOrigins(frame, CFRangeMake(lastLineIndex, 1), &lastLineOrigin);
      
                  // The height needed to draw the text is from the bottom of the last line
                  // to the top of the frame.
      
                  textHeight =  CGRectGetMaxY(frameRect) - lastLineOrigin.y + descent;
              }
          }
      
          // For some text the exact typographic bounds is a fraction of a point too
          // small to fit the text when it is put into a context. We go ahead and round
          // the returned drawing area up to the nearest point.  This takes care of the
          // discrepencies.
      
          return CGSizeMake(ceil(maxWidth), ceil(textHeight));
      }
      

      参考:斯科特·汤普森 (http://lists.apple.com/archives/quartz-dev/2008/Mar/msg00079.html)

      【讨论】:

        【解决方案4】:

        您可以使用 [NSString boundingRectWithSize:options:attributes:context:] 来获取字符串边界框的矩形,它也允许多行文本。 在您的绘制文本方法中,执行以下操作(RECT 是您要在其中绘制文本的矩形):

        // get the graphics context
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSaveGState(context);
        
        // flip the context coordinate
        CGContextTranslateCTM(context, 0.0f, 2*RECT.origin.y+RECT.size.height);
        CGContextScaleCTM(context, 1.0f, -1.0f);
        
        // Set the text matrix.
        CGContextSetTextMatrix(context, CGAffineTransformIdentity);
        
        // set text horizontal alignment
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.alignment = NSTextAlignmentCenter;
        
        NSDictionary *attributes = @{NSParagraphStyleAttributeName:paragraphStyle, NSFontAttributeName:YOUR_FONT, NSForegroundColorAttributeName:TEXT_COLOR};
        NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:YOUR_TEXT attributes:attributes];
        
        CGMutablePathRef path = CGPathCreateMutable();
        
        // set text vertical alignment
        CGSize textSize = [text boundingRectWithSize:RECT.size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
        CGPathAddRect(path, NULL, CGRectMake(RECT.origin.x, RECT.origin.y-(RECT.size.height-textSize.height)/2.0f, RECT.size.width, RECT.size.height));
        
        CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString);
        CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, attrString.length), path, NULL);
        CTFrameDraw(frame, context);
        
        CFRelease(frame);
        CFRelease(path);
        CFRelease(frameSetter);
        
        [attrString release];
        [paragraphStyle release];
        
        CGContextRestoreGState(context);
        

        【讨论】:

          猜你喜欢
          • 2020-06-25
          • 2018-11-12
          • 2012-08-15
          • 1970-01-01
          • 2014-10-27
          • 2020-01-23
          • 1970-01-01
          • 1970-01-01
          • 2019-02-09
          相关资源
          最近更新 更多