Полностью рабочее решение см. В нижней части моего ответа 100
Чтобы вручную измерить размеры text
/ attributedText
вашего UILabel
, чтобы найти подходящий размер шрифта, используя собственную стратегию, у вас есть несколько вариантов:
Используйте функцию NSString
size(withAttributes:)
или NSAttributedString
size()
. Они только частично полезны, поскольку предполагают, что текст состоит из одной строки.
Используйте функцию NSAttributedString
boundingRect()
, которая использует несколько параметров рисования, гарантируя, что вы предоставите .usesLineFragmentOrigin
для поддержки нескольких строк:
var textToMeasure = label.attributedText
// Modify the font size in `textToMeasure` as necessary
// Now measure
let rect = textToMeasure.boundingRect(with: label.bounds, options: [. usesLineFragmentOrigin], context: nil)
Используйте TextKit и собственный NSLayoutManager:
var textToMeasure = label.attributedText
// Modify the font size in `textToMeasure` as necessary
// Now measure
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: CGSize(width: label.bounds.width, height: .greatestFiniteMagnitude))
let textStorage = NSTextStorage(attributedString: string)
textStorage.addLayoutManager(layoutManager)
layoutManager.addTextContainer(textContainer)
let glyphRange = layoutManager.glyphRange(for: textContainer)
let rect = layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
Используйте CoreText, более мощный и низкоуровневый API для размещения текста. Это, вероятно, было бы излишне сложно для этой задачи.
Независимо от того, что вы выберете для измерения текста, вам, вероятно, потребуется выполнить два прохода: первый проход - для учета длинных слов, которые не следует разбивать на несколько строк, где вам нужно будет найти наибольшее размер шрифта, который вмещает самое большое (самое длинное) слово в пределах границ метки. Во втором проходе вы можете продолжить поиск вниз от результата первого прохода, чтобы найти еще меньший размер шрифта, необходимый для размещения всего текста на этот раз.
При выполнении измерения самого большого слова (а не всего текста) вы не хотите ограничивать параметр ширины, который вы предоставляете для некоторых из вышеуказанных функций определения размера, иначе у системы не будет иного выбора, кроме как разбить Отдельное слово, которое вы дали, и верните неверные результаты для ваших целей. Вам нужно будет заменить аргумент ширины вышеприведенных методов на CGFloat.greatestFiniteMagnitude
:
- часть ширины аргумента размера
boundingRect()
.
- часть ширины аргумента размера
NSTextContainer()
.
Вам также нужно будет рассмотреть фактический алгоритм, который вы используете для поиска, так как измерение текста - дорогостоящая операция, а линейный поиск может быть слишком медленным, в зависимости от ваших потребностей. Если вы хотите быть более эффективным, вы можете вместо этого применить бинарный поиск. ?
Надежное рабочее решение, основанное на вышеизложенном, см. В моей инфраструктуре с открытым исходным кодом AccessibilityKit . Несколько примеров AKLabel
в действии:
Надеюсь, это поможет!