如何获取适合固定大小文本视图的属性文本范围
How to get the range of Attributed text that can fit in a constant size textview
我正在尝试确定适合恒定大小的属性文本的数量 textview.I 已尝试使用 CTFrameSetter,但我认为这仅在我们已经知道要添加的文本时才有用.
到目前为止我已经试过了
func numberOfCharactersThatFitTextView() -> Int {
let fontRef = CTFontCreateWithName(font!.fontName as CFString, font!.pointSize, nil)
let attributes = [kCTFontAttributeName : fontRef]
let attributedString = NSAttributedString(string: text!, attributes: attributes as [NSAttributedString.Key : Any])
let frameSetterRef = CTFramesetterCreateWithAttributedString(attributedString as CFAttributedString)
var characterFitRange: CFRange = CFRange()
CTFramesetterSuggestFrameSizeWithConstraints(frameSetterRef, CFRangeMake(0, 0), nil, CGSize(width: bounds.size.width, height: bounds.size.height), &characterFitRange)
return Int(characterFitRange.length)
}
编辑
有时候,我会想太多...
如果您只想获得适合的最大行数,您可以使用字体的 .lineHeight
属性:
// the height of your text view
let h: CGFloat = 160.0
// whatever your font is
let font: UIFont = .systemFont(ofSize: 24.0)
let maxLines: Int = Int(floor(h / font.lineHeight))
print("Max Number of Lines:", maxLines)
原答案
如果您想要适合给定 textView 高度的行数,您可以这样做...
首先,一个方便的扩展:
extension NSAttributedString {
func height(containerWidth: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: containerWidth, height: CGFloat.greatestFiniteMagnitude),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
return ceil(rect.size.height)
}
func width(containerHeight: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: CGFloat.greatestFiniteMagnitude, height: containerHeight),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
return ceil(rect.size.width)
}
}
然后,使用这个函数:
func numberOfLinesThatFit(inHeight height: CGFloat, withFont font: UIFont) -> Int {
let attributes: [NSAttributedString.Key : Any] = [.font : font]
var n: Int = 0
var str: String = "A"
var attStr: NSAttributedString = NSAttributedString(string: str, attributes: attributes)
// width just needs to be greater than one character width
var h: CGFloat = attStr.height(containerWidth: 200.0)
while h < height {
n += 1
str += "\nA"
attStr = NSAttributedString(string: str, attributes: attributes)
h = attStr.height(containerWidth: 200.0)
}
return n
}
并这样称呼它:
// whatever your font is
let font: UIFont = .systemFont(ofSize: 24.0)
// the height of your text view
let h: CGFloat = 160.0
let maxLines: Int = numberOfLinesThatFit(inHeight: h, withFont: font)
print("max lines:", maxLines)
我正在尝试确定适合恒定大小的属性文本的数量 textview.I 已尝试使用 CTFrameSetter,但我认为这仅在我们已经知道要添加的文本时才有用. 到目前为止我已经试过了
func numberOfCharactersThatFitTextView() -> Int {
let fontRef = CTFontCreateWithName(font!.fontName as CFString, font!.pointSize, nil)
let attributes = [kCTFontAttributeName : fontRef]
let attributedString = NSAttributedString(string: text!, attributes: attributes as [NSAttributedString.Key : Any])
let frameSetterRef = CTFramesetterCreateWithAttributedString(attributedString as CFAttributedString)
var characterFitRange: CFRange = CFRange()
CTFramesetterSuggestFrameSizeWithConstraints(frameSetterRef, CFRangeMake(0, 0), nil, CGSize(width: bounds.size.width, height: bounds.size.height), &characterFitRange)
return Int(characterFitRange.length)
}
编辑
有时候,我会想太多...
如果您只想获得适合的最大行数,您可以使用字体的 .lineHeight
属性:
// the height of your text view
let h: CGFloat = 160.0
// whatever your font is
let font: UIFont = .systemFont(ofSize: 24.0)
let maxLines: Int = Int(floor(h / font.lineHeight))
print("Max Number of Lines:", maxLines)
原答案
如果您想要适合给定 textView 高度的行数,您可以这样做...
首先,一个方便的扩展:
extension NSAttributedString {
func height(containerWidth: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: containerWidth, height: CGFloat.greatestFiniteMagnitude),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
return ceil(rect.size.height)
}
func width(containerHeight: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: CGFloat.greatestFiniteMagnitude, height: containerHeight),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
return ceil(rect.size.width)
}
}
然后,使用这个函数:
func numberOfLinesThatFit(inHeight height: CGFloat, withFont font: UIFont) -> Int {
let attributes: [NSAttributedString.Key : Any] = [.font : font]
var n: Int = 0
var str: String = "A"
var attStr: NSAttributedString = NSAttributedString(string: str, attributes: attributes)
// width just needs to be greater than one character width
var h: CGFloat = attStr.height(containerWidth: 200.0)
while h < height {
n += 1
str += "\nA"
attStr = NSAttributedString(string: str, attributes: attributes)
h = attStr.height(containerWidth: 200.0)
}
return n
}
并这样称呼它:
// whatever your font is
let font: UIFont = .systemFont(ofSize: 24.0)
// the height of your text view
let h: CGFloat = 160.0
let maxLines: Int = numberOfLinesThatFit(inHeight: h, withFont: font)
print("max lines:", maxLines)