Drawing rotated text with NSString drawInRect

前端 未结 5 1828
借酒劲吻你
借酒劲吻你 2020-11-29 04:09

I found this answer on how to draw rotated text with NSString drawInRect:, but I\'m not sure how it works since it only sort of works for me: https://discussions.apple.com/t

相关标签:
5条回答
  • 2020-11-29 04:37

    KoNew's Solution in 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))
    
    
        }
    
    
    }
    

    To use:

    let fieldFont = UIFont(name: "Helvetica Neue", size: 14)
    
    myNSString.drawWithBasePoint(CGPointMake(bounds.width/2, bounds.height/2), angle: CGFloat(-M_PI_2), font: fieldFont!)
    
    0 讨论(0)
  • 2020-11-29 04:38

    Here'a an updated and simplified version of KoNEW's answer. It preserves the state of the graphics context as a bonus. This is also a simple function instead of a String extension.

    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()
    }
    
    0 讨论(0)
  • 2020-11-29 04:44

    I think what's happening is that you're rotating the text to a location outside of the view because it rotates the context by pivoting on the origin.

    After your rotation you need to do a translation to move the context back into the view. In the example below, I rotate the context counterclockwise 90 degrees. Then I translate the tx of the context the distance of the height.

    - (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);
    }
    

    Note that you can also get the size of how the string will be rendered, which can help in doing calculations for the alignment of the text.

        CGSize stringSize = [string sizeWithFont:font]; 
    
    0 讨论(0)
  • 2020-11-29 04:55

    Thank for this post, and Chris's answer, and Arkadiusz's answer at another post.

    Finally, I solve this problem by a UILabel subclass, named MyVerticalLabel, and make it draw vertical text.

    @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 讨论(0)
  • 2020-11-29 04:56

    I solve this problem in next way.

    1) Declare category on NSString

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

    This category will draw text with given central point, in one line and with given font and angle.

    2) Implementation of this category is looks like:

    @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) Now i can use it in my [UIView drawRect:] method. For example, in a next way:

     -(void)drawRect:(CGRect)rect{
     NSString* example = @"Title";
     [example drawWithBasePoint:CGPointMake(0.0f, 0.0f)
                       andAngle:M_PI
                        andFont:[UIFont boldSystemFontOfSize:16.0]];
     }
    
    0 讨论(0)
提交回复
热议问题