Text pixelating after scaling animation on view layer

Viewed 55

I am using following class to create curved text to be added to a CALayer

class CurvedTextLayer: CALayer {
    override init() {
        super.init()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    override init(layer: Any) {
        super.init(layer: layer)
    }
    
    init(with bounds: CGRect) {
        super.init()
        
        self.frame = bounds
        self.setNeedsDisplay()
    }
    
    func update(bounds: CGRect) {
        self.frame = bounds
        self.setNeedsDisplay()
    }
    
    override func draw(in ctx: CGContext) {
        super.draw(in: ctx)
        
        UIGraphicsPushContext(ctx)
        ctx.translateBy(x: bounds.size.width / 2, y: bounds.size.height / 2)
        ctx.scaleBy(x: 1, y: -1)
        centreArcPerpendicular(text: "Hello round world", context: ctx, radius: 100, angle: 0, colour: UIColor.red, font: UIFont.systemFont(ofSize: 16), clockwise: true)
        centreArcPerpendicular(text: "Anticlockwise", context: ctx, radius: 100, angle: CGFloat(-Double.pi/2), colour: UIColor.red, font: UIFont.systemFont(ofSize: 16), clockwise: false)
        centre(text: "Hello flat world", context: ctx, radius: 0, angle: 0 , colour: UIColor.yellow, font: UIFont.systemFont(ofSize: 16), slantAngle: CGFloat(Double.pi/4))
        UIGraphicsPopContext()
        
    }
    
    func centreArcPerpendicular(text str: String, context: CGContext, radius r: CGFloat, angle theta: CGFloat, colour c: UIColor, font: UIFont, clockwise: Bool){

        let characters: [String] = str.map { String($0) }
        let l = characters.count
        let attributes = [NSAttributedString.Key.font: font]

        var arcs: [CGFloat] = []
        var totalArc: CGFloat = 0

        for i in 0 ..< l {
            arcs += [chordToArc(characters[i].size(withAttributes: attributes).width, radius: r)]
            totalArc += arcs[i]
        }

        
        let direction: CGFloat = clockwise ? -1 : 1
        let slantCorrection: CGFloat = clockwise ? -.pi / 2 : .pi / 2

        var thetaI = theta - direction * totalArc / 2

        for i in 0 ..< l {
            thetaI += direction * arcs[i] / 2
            centre(text: characters[i], context: context, radius: r, angle: thetaI, colour: c, font: font, slantAngle: thetaI + slantCorrection)
            thetaI += direction * arcs[i] / 2
        }
    }

    func chordToArc(_ chord: CGFloat, radius: CGFloat) -> CGFloat {
        return 2 * asin(chord / (2 * radius))
    }

    func centre(text str: String, context: CGContext, radius r: CGFloat, angle theta: CGFloat, colour c: UIColor, font: UIFont, slantAngle: CGFloat) {

        let attributes = [NSAttributedString.Key.foregroundColor: c, NSAttributedString.Key.font: font]
        context.saveGState()
        context.scaleBy(x: 1, y: -1)
        context.translateBy(x: r * cos(theta), y: -(r * sin(theta)))
        context.rotate(by: -slantAngle)
        let offset = str.size(withAttributes: attributes)
        context.translateBy (x: -offset.width / 2, y: -offset.height / 2)
        str.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes)
        context.restoreGState()
    }
}

In ViewController I add the layer as follows

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
        
    let sublayer = CurvedTextLayer(with: myView.bounds)
    myView.layer.insertSublayer(sublayer, at: 0)
    animate()
        
}

After this I add this animation

func animate() {
    
    let rotationAnimation = CABasicAnimation(keyPath: "transform.scale")
    rotationAnimation.fromValue = 1
    rotationAnimation.toValue = 2
    rotationAnimation.duration = 3
    rotationAnimation.fillMode = .forwards
    rotationAnimation.isRemovedOnCompletion = false
    
    myView.layer.add(rotationAnimation, forKey: "wateva")
    
}

After scaling I get this pixelated text.

pixelated text

How can I make it so that it doesn't look pixelated?

0 Answers
Related