web-dev-qa-db-ja.com

NSStringdrawInRectを使用して回転したテキストを描画する

NSString drawInRect:を使用して回転したテキストを描画する方法についてこの回答を見つけましたが、それが私にとっては一種の機能しかないため、どのように機能するかわかりません: https://discussions.Apple.com/thread/1779814 ?start = 0&tstart =

私のコードは次のようになります:

           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度下に描画されているのがわかります。線形グラデーションに沿ってテキストを垂直に描画したいと思います。だから、90度のM_PI/2を使えばそれができると思いました。しかし、私のテキストは表示されません。回転に対してさまざまな変換を試しましたが、M_PI/4やM_PI/8のように機能するのは一部だけのようです。 -M_PI/4を使用すると、テキストはx軸より45度上になり、M_PI/2はx軸より90度下になると思います。しかし、どちらも何もありません。

何かご意見は?ありがとう。

19
Crystal

何が起こっているのかというと、原点を中心に回転してコンテキストを回転させるため、テキストをビューの外側の場所に回転させていると思います。

回転した後、コンテキストをビューに戻すために変換を行う必要があります。以下の例では、コンテキストを反時計回りに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]; 
12
Chris Livdahl

私はこの問題を次の方法で解決します。

1)NSStringでカテゴリを宣言します

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

このカテゴリは、指定された中心点、1行、指定されたフォントと角度でテキストを描画します。

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]];
 }
18
KoNEW

これは、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()
}
9
Todd Fincannon

SwiftでのKoNewのソリューション:

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!)
6
John D.

この投稿に感謝します、そして クリスの答え 、そして 別の投稿でのアルカディウスの答え

最後に、この問題をUILabelという名前のMyVerticalLabelサブクラスで解決し、垂直方向のテキストを描画させます。

@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
1
AechoLiu