Skip to content

Instantly share code, notes, and snippets.

@zhuqling
Forked from cemolcay/ArcTextLayer.swift
Created May 13, 2019 23:41
Show Gist options
  • Save zhuqling/48fb96a58367f72c555fd0e46f289eb2 to your computer and use it in GitHub Desktop.
Save zhuqling/48fb96a58367f72c555fd0e46f289eb2 to your computer and use it in GitHub Desktop.
Draws a curved string on a CALayer with angle, radius and text that you give.
import UIKit
// swift port of stackoverflow answer
// http://stackoverflow.com/a/31301238/2048130
extension CGFloat {
/** Degrees to Radian **/
var degrees: CGFloat {
return self * (180.0 / .pi)
}
/** Radians to Degrees **/
var radians: CGFloat {
return self / 180.0 * .pi
}
}
func drawCurvedString(on layer: CALayer, text: NSAttributedString, angle: CGFloat, radius: CGFloat) {
var radAngle = angle.radians
let textSize = text.boundingRect(
with: CGSize(width: .max, height: .max),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
.integral
.size
let perimeter: CGFloat = 2 * .pi * radius
let textAngle: CGFloat = textSize.width / perimeter * 2 * .pi
var textRotation: CGFloat = 0
var textDirection: CGFloat = 0
if angle > CGFloat(10).radians, angle < CGFloat(170).radians {
// bottom string
textRotation = 0.5 * .pi
textDirection = -2 * .pi
radAngle += textAngle / 2
} else {
// top string
textRotation = 1.5 * .pi
textDirection = 2 * .pi
radAngle -= textAngle / 2
}
for c in 0..<text.length {
let letter = text.attributedSubstring(from: NSRange(c..<c+1))
let charSize = letter.boundingRect(
with: CGSize(width: .max, height: .max),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
.integral
.size
let letterAngle = (charSize.width / perimeter) * textDirection
let x = radius * cos(radAngle + (letterAngle / 2))
let y = radius * sin(radAngle + (letterAngle / 2))
let singleChar = drawText(
on: layer,
text: letter,
frame: CGRect(
x: (layer.frame.size.width / 2) - (charSize.width / 2) + x,
y: (layer.frame.size.height / 2) - (charSize.height / 2) + y,
width: charSize.width,
height: charSize.height))
layer.addSublayer(singleChar)
singleChar.transform = CATransform3DMakeAffineTransform(CGAffineTransform(rotationAngle: radAngle - textRotation))
radAngle += letterAngle
}
}
func drawText(on layer: CALayer, text: NSAttributedString, frame: CGRect) -> CATextLayer {
let textLayer = CATextLayer()
textLayer.frame = frame
textLayer.string = text
textLayer.alignmentMode = kCAAlignmentCenter
textLayer.contentsScale = UIScreen.main.scale
return textLayer
}
let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
drawCurvedString(
on: view.layer,
text: NSAttributedString(
string: "This is a test string",
attributes: [
NSForegroundColorAttributeName: UIColor.white,
NSFontAttributeName: UIFont.systemFont(ofSize: 15)
]),
angle: 0,
radius: 85)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment