问题
Suppose I have a clock app, and I want to label the hours with characters that could be in an arbitrary character set/font. I'd like to frame the character in a frame and fill it as much as possible. How can I do that? If I use a UILabel
, space gets inserted around the glyph. Here are examples showing two labels, both with the same font but with different characters. The Hebrew numerals all seem shorter than the Arabic numerals. Is there a way to determine the size of the glyphs or somehow push the glyphs out to fit the frame?
As you can see, the Hebrew numeral is shorter even though it's being added to a taller UILabel.
Edit: Since posting, I made a first pass of using core text to see if that could resolve my problem. It seems that it will not. See these illustrations comparing a Hebrew glyph to an Arabic numeral glyph. They yellow is the label bounds. The green is the glyph rectangle reported by core text. I was hoping to get a rectangle flush to the glyph, but it looks like the Hebrew glyphs include space above and beside what I expected to be the glyph. Is there something else I should be checking?
回答1:
I don't know if you use Obj-C or Swift, but you can paste this into a Swift Playground page to see the result:
Minor Edits
import UIKit
import CoreText
import PlaygroundSupport
class PathView: UIView {
var myPath: UIBezierPath?
override func draw(_ rect: CGRect) {
if let pth = myPath {
UIColor.red.setStroke()
// glyph path is inverted, so flip vertically
let flipY = CGAffineTransform(scaleX: 1, y: -1.0)
// glyph path may be offset on the x coord, and by the height (because it's flipped)
let translate = CGAffineTransform(translationX: -pth.bounds.origin.x, y: pth.bounds.size.height + pth.bounds.origin.y)
// apply the transforms
pth.apply(flipY)
pth.apply(translate)
// stroke the path
pth.stroke()
// print the modified path for debug / reference
print(pth)
}
}
}
class TestViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// blue background so we can see framing
view.backgroundColor = UIColor(red: 0.25, green: 0.5, blue: 01.0, alpha: 1.0)
// use a large font so we can see it easily
let font = UIFont(name: "Times", size: 160)!
// Hebrew character for 8
var unichars = [UniChar]("ח".utf16)
unichars = [UniChar]("י".utf16)
// init glyphs array
var glyphs = [CGGlyph](repeatElement(0, count: unichars.count))
let gotGlyphs = CTFontGetGlyphsForCharacters(font, &unichars, &glyphs, unichars.count)
if gotGlyphs {
// get the cgPath for the character
let cgpath = CTFontCreatePathForGlyph(font, glyphs[0], nil)!
// convert it to a UIBezierPath
let path = UIBezierPath(cgPath: cgpath)
var r = path.bounds
// let's show it at 40,40
r = r.offsetBy(dx: 40.0, dy: 40.0)
let pView = PathView(frame: r)
pView.backgroundColor = .white
pView.myPath = path
view.addSubview(pView)
// print bounds and path data for debug / reference
print("bounds of path:", path.bounds)
print()
print(path)
print()
}
}
}
let vc = TestViewController()
PlaygroundPage.current.liveView = vc
Lots of error checking / handling needed, but this may give you a good start on finding and using the bounds of the actual character glyphs (instead of the label frames).
Result:
来源:https://stackoverflow.com/questions/47290882/how-to-manage-text-glyph-boundary