Я уже давно борюсь с этим. Существуют API, которые дают нам размер границ для заданных атрибутов NSAttributedString
.
Но не существует прямого способа получить диапазон строк, который бы соответствовал заданным границам.
Мое требование - разместить очень длинную строку в нескольких постраничных представлениях (PDF не вариант и не прокрутка). Следовательно, я должен определить размер строки для каждого представления (те же границы).
После исследования я обнаружил, что CTFramesetterSuggestFrameSizeWithConstraints
и его друзья в Core Text могут помочь. Я попробовал подход , описанный здесь , но у получающихся диапазонов есть одна неприятная проблема:
Он игнорирует разрывы слов (другая проблема, не связанная с Базовым текстом, но мне бы очень хотелось посмотреть, есть ли какое-то решение и для этого).
Как правило, я хочу разбить текст на несколько UITextView
объектов, но не получить правильные атрибуты разделения строк.
Примечание:
Мои NSAttributedString
атрибуты следующие:
let attributes: [NSAttributedString.Key : Any] = [.foregroundColor : textColor, .font : font, .paragraphStyle : titleParagraphStyle]
(titleParagraphStyle
имеет lineBreakMode
, установленный на byWordWrapping
)
extension UITextView
{
func getStringSplits (fullString: String, attributes: [NSAttributedString.Key:Any]) -> [String]
{
let attributeString = NSAttributedString(string: fullString, attributes: attributes)
let frameSetterRef = CTFramesetterCreateWithAttributedString(attributeString as CFAttributedString)
var initFitRange:CFRange = CFRangeMake(0, 0)
var finalRange:CFRange = CFRangeMake(0, fullString.count)
var ranges: [Int] = []
repeat
{
CTFramesetterSuggestFrameSizeWithConstraints(frameSetterRef, initFitRange, attributes as CFDictionary, CGSize(width: bounds.size.width, height: bounds.size.height), &finalRange)
initFitRange.location += finalRange.length
ranges.append(finalRange.length)
}
while (finalRange.location < attributeString.string.count)
var stringSplits: [String] = []
var startIndex: String.Index = fullString.startIndex
for n in ranges
{
let endIndex = fullString.index(startIndex, offsetBy: n, limitedBy: fullString.endIndex) ?? fullString.endIndex
let theSubString = fullString[startIndex..<endIndex]
stringSplits.append(String(theSubString))
startIndex = endIndex
}
return stringSplits
}
}