I'm working on a draw
function which needs to draw the word 'crux' in the center of the current view and then draw a red box around the 'x' character like this:
My code to do this looks like this
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
// Flip the coordinate system
context.textMatrix = .identity
context.translateBy(x: 0, y: bounds.size.height)
context.scaleBy(x: 1.0, y: -1.0)
// Create the logo as an attributed string
let font = UIFont(name: "EntangledPlainBRK", size:self.bounds.size.width * 0.4)!
let attrs:[String:Any] = [
kCTForegroundColorAttributeName as String: UIColor.black.cgColor,
kCTFontAttributeName as String: font
]
let logo = NSMutableAttributedString(string: "crux", attributes: attrs)
// Work out the position of the logo in the view.
let path = CGMutablePath()
let textSize = logo.size()
let logoOrigin = CGPoint(x: (rect.width - textSize.width) / 2.0, y: (rect.height - textSize.height) / 2.0)
let logoRect = CGRect(origin: logoOrigin, size: logo.size())
path.addRect(logoRect)
// get the frame setters.
let framesetter = CTFramesetterCreateWithAttributedString(logo as CFAttributedString)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, logo.length), path, nil)
CTFrameDraw(frame, context)
// Set the text position of the context to the location of the run on screen.
var lineOrigins = [CGPoint] (repeating: .zero, count: 1)
CTFrameGetLineOrigins(frame, CFRange(), &lineOrigins)
let lineOrigin = lineOrigins[0]
context.textPosition = CGPoint(x:logoOrigin.x + lineOrigin.x, y:logoOrigin.y + lineOrigin.y)
// Get the position of the last character.
let lines = CTFrameGetLines(frame)
let line = unsafeBitCast(CFArrayGetValueAtIndex(lines, 0), to:CTLine.self)
let runs = CTLineGetGlyphRuns(line)
let run = unsafeBitCast(CFArrayGetValueAtIndex(runs, 0), to:CTRun.self)
let glyphPosition = CTRunGetImageBounds(run, context, CFRange(location:3, length:1))
// Draw a box around it.
context.setStrokeColor(UIColor.red.cgColor)
context.setLineWidth(2.0)
context.stroke(glyphPosition)
}
It took some time to work out and feels a bit messy. I was wondering if there are any Core Text experts out there who know some tricks to shorten this code.