如何管理文本字形边界

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

需要大量错误检查/处理,但这可能会给您一个良好的开端,让您找到并使用实际字符字形(而不是标签框架)的边界。

结果: