1

I'm woking on a project were I have to draw strings of text in a UIView. The problem is not drawing the Strings, but rotating them. I want the text to be drawn just above and at the same angle as the red line. Check illustration below:

illustration example:

enter image description here

Here is the code... (PS. All irrelevant code is removed)

class DrawView: UIView {

    override func draw(_ rect: CGRect) {

        let context = UIGraphicsGetCurrentContext()!

        // Adding a line here.
        context.move(to: CGPoint(x: 290, y: 650))
        context.addLine(to: CGPoint(x: 530, y: 530))
        context.strokePath()

        // Flipping the coordinate system
        context.textMatrix = .identity
        context.translateBy(x: 0, y: bounds.size.height)
        context.scaleBy(x: 1.0, y: -1.0)

        // Creating the text path.
        let path = CGMutablePath()
        // "x" and "y" equals the staring point of the line. "width" equals the length of the line.
        path.addRect(CGRect(x: 290, y: 650, width: 268, height: 30))

        // I have tried rotating with the method below, but it rotates with the anchor point at (0, 0) in the UIView.
        //context.rotate(by: 0.4636) //   0.4636 equals the angle of the red line in radians.

        // Setting the text justification to center.
        let justification = NSMutableParagraphStyle()
        justification.alignment = NSTextAlignment.center

        // Creating the attribute.
        let attribute = [NSAttributedStringKey.font:  UIFont(name: "Arial", size: 22.0)!,
                         NSAttributedStringKey.foregroundColor: UIColor.black,
                         NSAttributedStringKey.paragraphStyle: justification] as [NSAttributedStringKey : Any]?

        // Creating the string and setting up the frame.
        let attrString = NSAttributedString(string: "12032.00", attributes: attribute)
        let framesetter = CTFramesetterCreateWithAttributedString(attrString as CFAttributedString)
        let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attrString.length), path, nil)

        CTFrameDraw(frame, context)
    }
}
  • 3
    Did you try `CGAffineTransform(rotationAngle: -CGFloat.pi / 2)`? – Arnab May 30 '18 at 12:19
  • 1
    The title of your question is poorly worded. Strings & attributed strings do not have a rotation. They are a representation of text. Better to ask "How do I draw an NSAttributedString rotated around a specific point?" – Duncan C May 30 '18 at 12:21
  • Thank you for the constructive feedback @DuncanC, you are correct. – LarsErikWik May 30 '18 at 12:32
  • Hi @ArnabHore. Thank you for the reply. I have tried that, but it rotates each character around their individual anchor point. I want to rotate the string as a whole. – LarsErikWik May 30 '18 at 12:35
  • 1
    See also https://stackoverflow.com/questions/32771864/draw-text-along-circular-path-in-swift-for-ios/32785652#32785652 – Grimxn May 30 '18 at 12:50
  • Thank you for the tip @Grimxn. This was really helpful! Best regards – LarsErikWik May 31 '18 at 06:01

2 Answers2

4

Thanks to all of you I have finally figured it out, much thanks to @Grimxn. This is how I solved it:

// Set attributes.
let attribute = [NSAttributedStringKey.font:  UIFont(name: "Courier", size: 22.0)!] as [NSAttributedStringKey : Any]?
// Save current context.
context.saveGState()
// Move orgin.
context.translateBy(x: 290, y: 650)
// Rotate the coordinate system.
context.rotate(by: -0.4636)
// Create a string.
let str = "12300.10"
// Draw string.
str.draw(at: CGPoint(x: 0, y: 0), withAttributes: attribute)
// Restore to saved context.
context.restoreGState()
1

Rotation is always done at the current 0,0 point. If you want to rotate around a different center, you have to shift your matrix to put the desired point of rotation over the origin, rotate, and shift back.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Thanks for the reply! Any ideas on how I can get that done? – LarsErikWik May 30 '18 at 12:39
  • I told you what to do. Graph out what you're doing, and the desired point of rotation of your text. You'll need to use the call `context.translateBy()`, which you're already using. I don't know the output you're after, so I can't tell you how to do it. – Duncan C May 30 '18 at 13:11
  • Once again, thank you Duncan. I try to figure this out tomorrow. Best regards w1k – LarsErikWik May 30 '18 at 15:45
  • 1
    Manipulating transformation matrixes is *really* confusing. Remember that the order in which you apply transforms to a matrix matters. I suggest you read up on the subject. I sometimes have to diagram out each step in applying transforms to a matrix to figure out the correct order in which to apply them, and it's never easy for me. – Duncan C May 31 '18 at 13:03