我正在寻找一些关于如何使用
Swift2 for iOS9在一个圆圈边缘绘制简单的单行字符串的最新帮助/提示.我看到很旧的例子涉及旧的ObjC片段,而且仅限于OS X.这是否可以在iOS中使用自定义UIView子类的drawRect()方法?
我要说“你试了什么?”,但星期五下午我早点下班了,所以我借机翻译了我的旧ObjC代码.这里适合游乐场.把它放在你的UIView中应该是微不足道的.
斯威夫特2
请参阅下面的Swift 3更新…
- import UIKit
- func centreArcPerpendicularText(str: String,context: CGContextRef,radius r: CGFloat,angle theta: CGFloat,colour c: UIColor,font: UIFont,clockwise: Bool){
- // *******************************************************
- // This draws the String str around an arc of radius r,// with the text centred at polar angle theta
- // *******************************************************
- let l = str.characters.count
- let attributes = [NSFontAttributeName: font]
- var characters: [String] = [] // This will be an array of single character strings,each character in str
- var arcs: [CGFloat] = [] // This will be the arcs subtended by each character
- var totalArc: CGFloat = 0 // ... and the total arc subtended by the string
- // Calculate the arc subtended by each letter and their total
- for i in 0 ..< l {
- characters += [String(str[str.startIndex.advancedBy(i)])]
- arcs += [chordToArc(characters[i].sizeWithAttributes(attributes).width,radius: r)]
- totalArc += arcs[i]
- }
- // Are we writing clockwise (right way up at 12 o'clock,upside down at 6 o'clock)
- // or anti-clockwise (right way up at 6 o'clock)?
- let direction: CGFloat = clockwise ? -1 : 1
- let slantCorrection = clockwise ? -CGFloat(M_PI_2) : CGFloat(M_PI_2)
- // The centre of the first character will then be at
- // thetaI = theta - totalArc / 2 + arcs[0] / 2
- // But we add the last term inside the loop
- var thetaI = theta - direction * totalArc / 2
- for i in 0 ..< l {
- thetaI += direction * arcs[i] / 2
- // Call centerText with each character in turn.
- // Remember to add +/-90º to the slantAngle otherwise
- // the characters will "stack" round the arc rather than "text flow"
- centreText(characters[i],context: context,radius: r,angle: thetaI,colour: c,font: font,slantAngle: thetaI + slantCorrection)
- // The centre of the next character will then be at
- // thetaI = thetaI + arcs[i] / 2 + arcs[i + 1] / 2
- // but again we leave the last term to the start of the next loop...
- thetaI += direction * arcs[i] / 2
- }
- }
- func chordToArc(chord: CGFloat,radius: CGFloat) -> CGFloat {
- // *******************************************************
- // Simple geometry
- // *******************************************************
- return 2 * asin(chord / (2 * radius))
- }
- func centreText(str: String,radius r:CGFloat,slantAngle: CGFloat) {
- // *******************************************************
- // This draws the String str centred at the position
- // specified by the polar coordinates (r,theta)
- // i.e. the x= r * cos(theta) y= r * sin(theta)
- // and rotated by the angle slantAngle
- // *******************************************************
- // Set the text attributes
- let attributes = [NSForegroundColorAttributeName: c,NSFontAttributeName: font]
- // Save the context
- CGContextSaveGState(context)
- // Undo the inversion of the Y-axis (or the text goes backwards!)
- CGContextScaleCTM(context,1,-1)
- // Move the origin to the centre of the text (negating the y-axis manually)
- CGContextTranslateCTM(context,r * cos(theta),-(r * sin(theta)))
- // Rotate the coordinate system
- CGContextRotateCTM(context,-slantAngle)
- // Calculate the width of the text
- let offset = str.sizeWithAttributes(attributes)
- // Move the origin by half the size of the text
- CGContextTranslateCTM (context,-offset.width / 2,-offset.height / 2) // Move the origin to the centre of the text (negating the y-axis manually)
- // Draw the text
- str.drawAtPoint(CGPointZero,withAttributes: attributes)
- // Restore the context
- CGContextRestoreGState(context)
- }
- // *******************************************************
- // Playground code to test
- // *******************************************************
- let size = CGSize(width: 256,height: 256)
- UIGraphicsBeginImageContextWithOptions(size,true,0.0)
- let context = UIGraphicsGetCurrentContext()!
- // *******************************************************************
- // Scale & translate the context to have 0,0
- // at the centre of the screen maths convention
- // ObvIoUsly change your origin to suit...
- // *******************************************************************
- CGContextTranslateCTM (context,size.width / 2,size.height / 2)
- CGContextScaleCTM (context,-1)
- centreArcPerpendicularText("Hello round world",radius: 100,angle: 0,colour: UIColor.redColor(),font: UIFont.systemFontOfSize(16),clockwise: true)
- centreArcPerpendicularText("Anticlockwise",angle: CGFloat(-M_PI_2),clockwise: false)
- centreText("Hello flat world",radius: 0,colour: UIColor.yellowColor(),slantAngle: CGFloat(M_PI_4))
- let image = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
输出为:
更新
顺时针/逆时针方向直的例子
更新Swift 3
- func centreArcPerpendicular(text str: String,context: CGContext,// with the text centred at polar angle theta
- // *******************************************************
- let l = str.characters.count
- let attributes = [NSFontAttributeName: font]
- let characters: [String] = str.characters.map { String($0) } // An array of single character strings,each character in str
- var arcs: [CGFloat] = [] // This will be the arcs subtended by each character
- var totalArc: CGFloat = 0 // ... and the total arc subtended by the string
- // Calculate the arc subtended by each letter and their total
- for i in 0 ..< l {
- arcs += [chordToArc(characters[i].size(attributes: attributes).width,upside down at 6 o'clock)
- // or anti-clockwise (right way up at 6 o'clock)?
- let direction: CGFloat = clockwise ? -1 : 1
- let slantCorrection = clockwise ? -CGFloat(M_PI_2) : CGFloat(M_PI_2)
- // The centre of the first character will then be at
- // thetaI = theta - totalArc / 2 + arcs[0] / 2
- // But we add the last term inside the loop
- var thetaI = theta - direction * totalArc / 2
- for i in 0 ..< l {
- thetaI += direction * arcs[i] / 2
- // Call centerText with each character in turn.
- // Remember to add +/-90º to the slantAngle otherwise
- // the characters will "stack" round the arc rather than "text flow"
- centre(text: characters[i],slantAngle: thetaI + slantCorrection)
- // The centre of the next character will then be at
- // thetaI = thetaI + arcs[i] / 2 + arcs[i + 1] / 2
- // but again we leave the last term to the start of the next loop...
- thetaI += direction * arcs[i] / 2
- }
- }
- func chordToArc(_ chord: CGFloat,radius: CGFloat) -> CGFloat {
- // *******************************************************
- // Simple geometry
- // *******************************************************
- return 2 * asin(chord / (2 * radius))
- }
- func centre(text str: String,NSFontAttributeName: font]
- // Save the context
- context.saveGState()
- // Undo the inversion of the Y-axis (or the text goes backwards!)
- context.scaleBy(x: 1,y: -1)
- // Move the origin to the centre of the text (negating the y-axis manually)
- context.translateBy(x: r * cos(theta),y: -(r * sin(theta)))
- // Rotate the coordinate system
- context.rotate(by: -slantAngle)
- // Calculate the width of the text
- let offset = str.size(attributes: attributes)
- // Move the origin by half the size of the text
- context.translateBy (x: -offset.width / 2,y: -offset.height / 2) // Move the origin to the centre of the text (negating the y-axis manually)
- // Draw the text
- str.draw(at: CGPoint(x: 0,y: 0),withAttributes: attributes)
- // Restore the context
- context.restoreGState()
- }
- // *******************************************************
- // Playground code to test
- // *******************************************************
- let size = CGSize(width: 256,0
- // at the centre of the screen maths convention
- // ObvIoUsly change your origin to suit...
- // *******************************************************************
- context.translateBy (x: size.width / 2,y: size.height / 2)
- context.scaleBy (x: 1,y: -1)
- centreArcPerpendicular(text: "Hello round world",colour: UIColor.red,font: UIFont.systemFont(ofSize: 16),clockwise: true)
- centreArcPerpendicular(text: "Anticlockwise",clockwise: false)
- centre(text: "Hello flat world",colour: UIColor.yellow,slantAngle: CGFloat(M_PI_4))
- let image = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
更新以在UIView中显示使用
评论员@RitvikUpadhyaya询问如何在UIView中做到这一点 – 对老手来说显而易见,但不是初学者.诀窍是使用UIGraphicsGetCurrentContext获取正确的上下文,而无需调用UIGraphicsBeginImageContextWithOptions(将UIView的上下文替换为当前上下文) – 因此您的UIView应该如下所示:
- class MyView: UIView {
- override func draw(_ rect: CGRect) {
- guard let context = UIGraphicsGetCurrentContext() else { return }
- let size = self.bounds.size
- context.translateBy (x: size.width / 2,y: size.height / 2)
- context.scaleBy (x: 1,y: -1)
- centreArcPerpendicular(text: "Hello round world",clockwise: true)
- centreArcPerpendicular(text: "Anticlockwise",clockwise: false)
- centre(text: "Hello flat world",slantAngle: CGFloat(M_PI_4))
- }
- }