如何管理文本字形边界
How to manage text glyph boundary
假设我有一个时钟应用程序,我想用可以是任意字符的字符来标记时间 set/font。我想将角色框在一个框架中并尽可能地填充它。我怎样才能做到这一点?如果我使用 UILabel
,space 会插入字形周围。下面是显示两个标签的示例,它们都具有相同的字体但具有不同的字符。希伯来数字似乎都比阿拉伯数字短。有没有办法确定字形的大小或以某种方式将字形推出以适合框架?
如您所见,希伯来数字更短,即使它被添加到更高的 UILabel。
编辑:自发布以来,我第一次使用核心文本来查看是否可以解决我的问题。好像不会。请参阅这些比较希伯来字形和阿拉伯数字字形的插图。他们黄色是标签边界。绿色是核心文本报告的字形矩形。我希望得到一个与字形齐平的矩形,但看起来希伯来字形在我预期的字形上方和旁边包含 space。还有什么我应该检查的吗?
我不知道你使用的是 Obj-C 还是 Swift,但你可以将其粘贴到 Swift 游乐场页面以查看结果:
小修改
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
需要大量错误检查/处理,但这可能会给您一个良好的开端,让您找到并使用实际字符字形(而不是标签框架)的边界。
结果:
假设我有一个时钟应用程序,我想用可以是任意字符的字符来标记时间 set/font。我想将角色框在一个框架中并尽可能地填充它。我怎样才能做到这一点?如果我使用 UILabel
,space 会插入字形周围。下面是显示两个标签的示例,它们都具有相同的字体但具有不同的字符。希伯来数字似乎都比阿拉伯数字短。有没有办法确定字形的大小或以某种方式将字形推出以适合框架?
如您所见,希伯来数字更短,即使它被添加到更高的 UILabel。
编辑:自发布以来,我第一次使用核心文本来查看是否可以解决我的问题。好像不会。请参阅这些比较希伯来字形和阿拉伯数字字形的插图。他们黄色是标签边界。绿色是核心文本报告的字形矩形。我希望得到一个与字形齐平的矩形,但看起来希伯来字形在我预期的字形上方和旁边包含 space。还有什么我应该检查的吗?
我不知道你使用的是 Obj-C 还是 Swift,但你可以将其粘贴到 Swift 游乐场页面以查看结果:
小修改
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
需要大量错误检查/处理,但这可能会给您一个良好的开端,让您找到并使用实际字符字形(而不是标签框架)的边界。
结果: