Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit the number of characters in a String or attributed String in Swift

Tags:

string

swift

Given is a (html) String with x-number of characters. The String will get formatted into an attributed String. Then displayed in a UILabel.

The UILabel has a height of >= 25 and <= 50 to limit the number of lines to 2.

Since the String has characters not visible in the formatted attributed String, like <b> / <i>, the best approach would be to limit the character count of the attributed String.

UILabel property .lineBreakMode = .byTruncatingTail causes words to get cut.

enter image description here

The goal, in case the character count would exceed the limit of space in the UILabel, is to cut between words. Desired maxCharacterCount = 50. Determine the last space before maxCharacterCount. Cut the String and append ... as last characters of the UILabel.

What's the best approach to limit the characters? Help is very appreciate.

like image 267
David Seek Avatar asked Apr 12 '17 20:04

David Seek


2 Answers

Start with the full string and the known two-line height of the label and its known width, and keep cutting words off the end of the string until, at that width, the string's height is less than the label's height. Then cut one more word off the end for good measure, append the ellipsis, and put the resulting string into the label.

In that way, I got this:

enter image description here

Notice that the word after "time" never starts; we stop at a precise word-end with the inserted ellipsis. Here's how I did that:

    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
        }
    }

It is of course possible to be much more sophisticated about what constitutes a "word" and in the conditions for measurement, but the above demonstrates the general common technique for this sort of thing and should suffice to get you started.

like image 168
matt Avatar answered Oct 27 '22 07:10

matt


try this:

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.
}


}

string width calculation link

like image 37
Mikael Weiss Avatar answered Oct 27 '22 07:10

Mikael Weiss