-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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