Как ограничить количество символов в String или атрибутной строке в Swift

Предоставлена ​​строка (html) с x-числом символов. Строка будет отформатирована в атрибут String. Затем отображается в UILabel.

UILabel имеет высоту >= 25 и <= 50, чтобы ограничить количество строк до 2.

Так как String имеет символы, которые не видны в форматированной атрибутной строке, например <b> / <i>, лучшим способом было бы ограничить количество символов приписываемой строки.

UILabel Свойство .lineBreakMode = .byTruncatingTail вызывает сокращение слов.

введите описание изображения здесь

Цель, если количество символов превысит предел пространства в UILabel, будет вырезать между словами. Желаемый maxCharacterCount = 50. Определите последний space до maxCharacterCount. Вырежьте строку и добавьте ... в качестве последних символов UILabel.

Какой лучший подход к ограничению персонажей? Помощь очень ценится.

Ответ 1

Начните с полной строки и известной двухстрочной высоты метки и ее известной ширины и продолжайте вырезать слова с конца строки до тех пор, пока на этой ширине высота строки будет меньше высоты метки. Затем отделите еще одно слово от конца для хорошей меры, добавьте многоточие и поместите полученную строку в метку.

Таким образом, я получил следующее:

введите описание изображения здесь

Обратите внимание, что слово "время" никогда не начинается; мы останавливаемся на точном конце слова с вставленным эллипсисом. Вот как я это сделал:

    lab.numberOfLines = 2
    let s = "Little poltergeists make up the principle form of material " +
        "manifestation. Now is the time for all good men to come to the " +
        "aid of the country."
    let atts = [NSFontAttributeName: UIFont(name: "Georgia", size: 18)!]
    let arr = s.components(separatedBy: " ")
    for max in (1..<arr.count).reversed() {
        let s = arr[0..<max].joined(separator: " ")
        let attrib = NSMutableAttributedString(string: s, attributes: atts)
        let height = attrib.boundingRect(with: CGSize(width:lab.bounds.width, 
                                                      height:10000),
                                         options: [.usesLineFragmentOrigin],
                                         context: nil).height
        if height < lab.bounds.height {
            let s = arr[0..<max-1].joined(separator: " ") + "…"
            let attrib = NSMutableAttributedString(string: s, attributes: atts)
            lab.attributedText = attrib
            break
        }
    }

Конечно, можно быть намного более изощренным в том, что составляет "слово" и в условиях измерения, но приведенное выше демонстрирует общую общую технику для такого рода вещей и должно быть достаточно, чтобы вы начали.

Ответ 2

попробуйте следующее:

import UIKit

class ViewController: UIViewController {
var str = "Hello, playground"
var thisInt = 10
@IBOutlet weak var lbl: UILabel!
var lblWidth : CGFloat = 0.0

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    lblWidth = lbl.bounds.width

    while str.characters.count <= thisInt - 3 {
        str.remove(at: str.index(before: str.endIndex))
        str.append("...")
    }
    lbl.text = str
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

ссылка для расчета ширины строки

Ответ 3

Только для записи Ответ Matt отвечает правильно, но вы можете удалить любые возможные проблемы, создав свой собственный подкласс UILabel, который сохранит исходное значение в переменной. Затем вы можете обновить свой макет из контроллера просмотра при изменении ориентации.