ios - 核心文本 : Simplest accurate means of getting text bounds?

标签 ios swift macos core-text

问题:

使用 Core Text 获取给定文本行边界的最简单准确方法是什么?

问题:

我尝试了多种技术,但得到的结果不一致。

上下文:

我一直在努力弄清楚如何找到目前单行文本的实际范围。

Core Text 文档在框架、行和运行级别例程返回什么方面充其量是不完整的,声明它们返回“实际”边界,而实际上它们不同意(至少在框架级别),并且不' 返回特定字符串的实际边界,但返回的大小似乎大于字体大小的预测值。

但是,当我获得单个字形的边界时,我确实看到了不同字符之间的差异,这表明这是唯一准确的方法(遍历所有字形,找到它们的有效并集)。

我已经在 playground 文件中编写了一些测试,我是否遗漏了一些明显的东西?我的最终目标(部分/大部分工作)是拥有一个自定义 CALayer,它接受一个属性字符串,并将其缩放以填充整个边界。这与自动布局配合得很好,因为我可以根据需要创建一个随布局缩放的标签。

下面是我的 playground 片段,请注意右栏中生成的值。

// Playground - noun: a place where people can play

import UIKit
import CoreText
import QuartzCore

print("start")



let f = UIFont.systemFontOfSize(12)
let t = NSAttributedString(string: "A", attributes: [NSFontAttributeName:f])
let line = CTLineCreateWithAttributedString(t)
var ascent:CGFloat = 0, descent:CGFloat = 0, leading:CGFloat = 0
CTLineGetTypographicBounds(line, &ascent, &descent, &leading)
ascent
descent
ascent + descent
leading

let boundingSize = CGSizeMake(CGFloat.max, CGFloat.max)
let fs = CTFramesetterCreateWithAttributedString(t)
let frameSize = CTFramesetterSuggestFrameSizeWithConstraints(fs, CFRangeMake(0, t.length),
    nil, boundingSize, nil)
frameSize
let lineWidth = frameSize.width
let lineHeight = frameSize.height


// for each run
let runs = CTLineGetGlyphRuns(line) as [AnyObject] as! [CTRun]
for (runIndex, run) in runs.enumerate() {

    // get font
    let attributes = CTRunGetAttributes(run) as NSDictionary as! [String:AnyObject]
    let runFont:CTFont = attributes[kCTFontAttributeName as String] as! CTFont

    // get glyphs for current run
    let glyphCount = CTRunGetGlyphCount(run)
    let range = CFRangeMake(0, glyphCount)
    var glyphs = Array<CGGlyph>(count: glyphCount, repeatedValue: CGGlyph())
    var positions = [CGPoint](count: glyphCount, repeatedValue: CGPointZero)
    CTRunGetGlyphs(run, range, &glyphs)
    CTRunGetPositions(run, range, &positions)

    let runWidth = CTRunGetTypographicBounds(run, range, &ascent, &descent, &leading)
    runWidth

    ascent
    descent
    leading

    // for each glyph in run
    for (glyphInRun, var glyph) in glyphs.enumerate() {

        let glyphFrame = withUnsafePointer(&glyph) { pointer -> CGRect in
            return CTFontGetBoundingRectsForGlyphs(runFont, .Default, pointer, nil, 1) }
        glyphFrame.size
    }
}



print("done")

谢谢!

最佳答案

您正在使用 CTRunGetTypographicBounds。排版边界是指用于排版的边界,因此上升、下降和前进是基于字体规范,而不是运行中字形的实际外观。

听起来您想要 CTRunGetImageBounds,它返回一个“紧密包围运行字形路径”的 CGRect。请注意,您可以为上下文参数传递 nil(在我的测试中)。

关于ios - 核心文本 : Simplest accurate means of getting text bounds?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33509662/

相关文章:

ios - 调整 UITableView 的大小以适应内容

ios - 如何将 UIViewController 推送到 UISplitViewController

ios - 这是对属性使用 self 属性的正确方法吗?

ios - 如何使用 MVVM 处理 UITableViewCell 中的 UICollectionView

string - Swift 字符串去掉除数字和小数点以外的所有字符?

swift - Swiftui 中 init() 中的变量前的下划线是什么意思?

macos - 为什么 SwiftUI 列表行被选中但未突出显示 (MacOS)

java - 如何在 Mac OS 的 Java 中获取 User ~/Library 路径

ruby - Homebrew 如何检查已安装的 gem?

ios - 在动态表中重新加载 TableViewCell 的 UILabels