使用 NSString drawInRect 绘制旋转文本

问题描述 投票:0回答:7

我找到了关于如何使用 NSString drawInRect: 绘制旋转文本的答案,但我不确定它是如何工作的,因为它只对我有用:https://discussions.apple.com/thread/1779814?start =0&t开始=0

我的代码如下所示:

           CGContextSaveGState(context);
           CGContextDrawLinearGradient(context, gradient, CGPointMake(0, centY - halfWidth), CGPointMake(0, centY + halfWidth), 0);

            // Add text                
            CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); 
            NSString *str = @"some test string";

            CGAffineTransform transform1 = CGAffineTransformMakeRotation(M_PI/4);

            CGContextConcatCTM(context, transform1);
            CGContextTranslateCTM(context, 0, 0);
            UIFont *font = [UIFont systemFontOfSize:16.0];

            [str drawInRect:CGRectMake(0, 0, 200, 100) withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UIBaselineAdjustmentNone];

所以当我使用它时,我看到文本被绘制在 x 轴下方 45 度的位置。我想沿着我的线性渐变垂直绘制文本。所以我想我可以通过使用 M_PI/2 90 度来做到这一点。但我没有看到我的文字。我尝试了不同的旋转变换,但只有一些似乎可以工作,例如 M_PI/4 和 M_PI/8。我认为如果我使用 -M_PI/4 ,文本将在 x 轴上方 45 度,而 M_PI/2 将在 x 轴下方 90 度。但两者都一无所获。

有什么想法吗?谢谢。

iphone quartz-graphics
7个回答
19
投票

我用下面的方法解决这个问题。

1)在 NSString 上声明类别

@interface NSString (NMSchemeItemDraw)
-(void)  drawWithBasePoint:(CGPoint)basePoint
                    andAngle:(CGFloat)angle
                     andFont:(UIFont*)font;
@end

此类别将使用给定的中心点、一行、给定的字体和角度绘制文本。

2)该类别的实现如下所示:

@implementation NSString (NMSchemeItemDraw)

    -(void)  drawWithBasePoint:(CGPoint)basePoint
                     andAngle:(CGFloat)angle
                      andFont:(UIFont *)font{
    CGSize  textSize    =   [self   sizeWithFont:font];

    CGContextRef    context =   UIGraphicsGetCurrentContext();
    CGAffineTransform   t   =   CGAffineTransformMakeTranslation(basePoint.x, basePoint.y);
    CGAffineTransform   r   =   CGAffineTransformMakeRotation(angle);


    CGContextConcatCTM(context, t);
    CGContextConcatCTM(context, r);

    [self   drawAtPoint:CGPointMake(-1 * textSize.width / 2, -1 * textSize.height / 2)
               withFont:font];

    CGContextConcatCTM(context, CGAffineTransformInvert(r));
    CGContextConcatCTM(context, CGAffineTransformInvert(t));
    }
@end

3)现在我可以在我的

[UIView drawRect:]
方法中使用它。 例如,以下一种方式:

 -(void)drawRect:(CGRect)rect{
 NSString* example = @"Title";
 [example drawWithBasePoint:CGPointMake(0.0f, 0.0f)
                   andAngle:M_PI
                    andFont:[UIFont boldSystemFontOfSize:16.0]];
 }

13
投票

我认为发生的情况是您将文本旋转到视图之外的位置,因为它通过以原点为中心旋转上下文。

旋转后,您需要进行翻译以将上下文移回到视图中。在下面的示例中,我将上下文逆时针旋转 90 度。然后我将上下文的 tx 翻译为高度的距离。

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    CGContextSaveGState(context);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // Create the gradient 
    CGColorRef startColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0].CGColor; 
    CGColorRef endColor = [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:1.0].CGColor;
    NSArray *colors = [NSArray arrayWithObjects:(id)startColor, (id)endColor, nil];
    CGFloat locations[] = { 0.0, 1.0 };
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef) colors, locations);
    CGContextDrawLinearGradient(context, gradient, CGPointMake(rect.origin.x + rect.size.width / 2, rect.origin.y), CGPointMake(rect.origin.x + rect.size.width / 2, rect.origin.y + rect.size.height), 0);

    // Create text              
    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); 
    NSString *string = @"some test string";
    UIFont *font = [UIFont systemFontOfSize:16.0];

    // Rotate the context 90 degrees (convert to radians)
    CGAffineTransform transform1 = CGAffineTransformMakeRotation(-M_PI_2);
    CGContextConcatCTM(context, transform1); 

    // Move the context back into the view 
    CGContextTranslateCTM(context, -rect.size.height, 0);

    // Draw the string 
    [string drawInRect:rect withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft];

    // Clean up 
    CGGradientRelease(gradient);
    CGColorSpaceRelease(colorSpace);

    CGContextRestoreGState(context);
}

请注意,您还可以获得字符串呈现方式的大小,这有助于计算文本的对齐方式。

    CGSize stringSize = [string sizeWithFont:font]; 

13
投票

这是 KoNEW 答案的更新和简化版本。作为奖励,它保留了图形上下文的状态。这也是一个简单的函数,而不是字符串扩展。

func drawRotatedText(_ text: String, at p: CGPoint, angle: CGFloat, font: UIFont, color: UIColor) {
  // Draw text centered on the point, rotated by an angle in degrees moving clockwise.
  let attrs = [NSFontAttributeName: font, NSForegroundColorAttributeName: color]
  let textSize = text.size(attributes: attrs)
  let c = UIGraphicsGetCurrentContext()!
  c.saveGState()
  // Translate the origin to the drawing location and rotate the coordinate system.
  c.translateBy(x: p.x, y: p.y)
  c.rotate(by: angle * .pi / 180)
  // Draw the text centered at the point.
  text.draw(at: CGPoint(x: -textSize.width / 2, y: -textSize.height / 2), withAttributes: attrs)
  // Restore the original coordinate system.
  c.restoreGState()
}

6
投票

KoNew 在 Swift 中的解决方案:

extension NSString {

    func drawWithBasePoint(basePoint:CGPoint, angle:CGFloat, font:UIFont) {

        var attrs: NSDictionary = [
            NSFontAttributeName: font
        ]

        var textSize:CGSize = self.sizeWithAttributes(attrs as [NSObject : AnyObject])

        // sizeWithAttributes is only effective with single line NSString text 
        // use boundingRectWithSize for multi line text

        var context: CGContextRef =   UIGraphicsGetCurrentContext()

        var t:CGAffineTransform   =   CGAffineTransformMakeTranslation(basePoint.x, basePoint.y)
        var r:CGAffineTransform   =   CGAffineTransformMakeRotation(angle)


        CGContextConcatCTM(context, t)
        CGContextConcatCTM(context, r)


        self.drawAtPoint(CGPointMake(-1 * textSize.width / 2, -1 * textSize.height / 2), withAttributes: attrs as [NSObject : AnyObject])


        CGContextConcatCTM(context, CGAffineTransformInvert(r))
        CGContextConcatCTM(context, CGAffineTransformInvert(t))


    }


}

使用方法:

let fieldFont = UIFont(name: "Helvetica Neue", size: 14)

myNSString.drawWithBasePoint(CGPointMake(bounds.width/2, bounds.height/2), angle: CGFloat(-M_PI_2), font: fieldFont!)

1
投票

感谢这篇文章,以及Chris的回答,以及Arkadiusz在另一篇文章中的回答

最后,我通过一个名为

UILabel
的子类解决了这个问题,并使其绘制垂直文本。

MyVerticalLabel



1
投票

@implementation MyVerticalLabel // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code CGContextRef context = UIGraphicsGetCurrentContext(); CGAffineTransform transform = CGAffineTransformMakeRotation(-M_PI_2); CGContextConcatCTM(context, transform); CGContextTranslateCTM(context, -rect.size.height, 0); // The drawing rect should be applied with transform to. CGRect newRect = CGRectApplyAffineTransform(rect, transform); newRect.origin = CGPointZero; NSMutableParagraphStyle *textStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy]; textStyle.lineBreakMode = self.lineBreakMode; textStyle.alignment = self.textAlignment; // Apply current label attributes for drawing function. NSDictionary *attributeDict = @{ NSFontAttributeName : self.font, NSForegroundColorAttributeName : self.textColor, NSParagraphStyleAttributeName : textStyle, }; [self.text drawInRect:newRect withAttributes:attributeDict]; } @end



0
投票
以在 UIImage 上快速绘制旋转文本为例

用途:

enum StringOrigin: Int { case upperLeft, upperCenter, upperRight, centerLeft, centerCenter, centerRight, lowerLeft, lowerCenter, lowerRight } func drawRotatedAttrString(_ s: NSAttributedString, p: CGPoint, angle: CGFloat, origin: StringOrigin) { let width = s.size().width let height = s.size().height let c = UIGraphicsGetCurrentContext()! c.saveGState() // Translate the origin to the drawing location and rotate the coordinate system. c.translateBy(x: p.x, y: p.y) c.rotate(by: angle * .pi / 180) // Draw the text offset to handle "origin" choice switch origin { case .upperLeft: s.draw(at: .zero) case .upperCenter: s.draw(at: CGPoint(x: -0.5 * width, y: 0)) case .upperRight: s.draw(at: CGPoint(x: -width, y: 0)) case .centerLeft: s.draw(at: CGPoint(x: 0, y: -0.5 * height)) case .centerCenter: s.draw(at: CGPoint(x: -0.5 * width, y: -0.5 * height)) case .centerRight: s.draw(at: CGPoint(x: -width, y: -0.5 * height)) case .lowerLeft: s.draw(at: CGPoint(x: 0, y: -height)) case .lowerCenter: s.draw(at: CGPoint(x: -0.5 * width, y: -height)) case .lowerRight: s.draw(at: CGPoint(x: -width, y: -height)) } // Restore the original coordinate system. c.restoreGState() }

self.someImageView.image = UIImage(named: "icon")?.addTopRightVerticalText("Hello World")
© www.soinside.com 2019 - 2024. All rights reserved.