Search code examples
iosswiftuilabelnsattributedstringparagraph

How to show numbers for each paragraph in Swift label


I am getting string from server is like below, Due to privacy policy I have added some static text.

"\n1. You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen . \n2. You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen \n3. You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen…\n"

The above text I have to show like below format.

1. You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen .

2. You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen

3. You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen…

Also the index numbers should have different color to show in label.

Any suggestions?


Solution

  • First, the \n character is a newline character, so it will be handled by the UILabel for you. So, all you need to do is to set the foregroundColor for matches of the number at the start of each line. E.g.

    let string = "\n1. You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen . \n2. You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen \n3. You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen…\n"
        .trimmingCharacters(in: .whitespacesAndNewlines)
        .replacingOccurrences(of: "\n", with: "\n\n")
    
    let attributedString = NSMutableAttributedString(string: string)
    
    let regex = try! NSRegularExpression(pattern: #"^\d+\."#, options: .anchorsMatchLines)
    let range = NSRange(location: 0, length: attributedString.length)
    regex.enumerateMatches(in: string, range: range) { result, _, _ in
        guard let range = result?.range else { return }
        attributedString.addAttribute(.foregroundColor, value: UIColor.red, range: range)
    }
    
    label.numberOfLines = 0
    label.attributedText = attributedString
    

    That will yield:

    enter image description here

    That includes a border (rendered with with label.layer.borderColor and layer.borderWidth), so you can see precisely how the text is laid out in the label.


    If you want it to look like a real list, with indentation, you would probably have to reformat the text into HTML (which would, itself, be an annoying exercise), then back to a NSAttributedString and format the numbers there:

    
    let string = """
        <style>
        li {
            color: white;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 12pt;
            margin-bottom: 12pt;
        }
        </style>
        <ol>
        <li>You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen .</li>
        <li>You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen</li>
        <li>You are Lorem ipsum doller sit amen Lorem ipsum doller sit amen Lorem ipsum doller sit amen…</li>
        </ol>
        """
    guard let data = string.data(using: .utf16) else { return }
    
    let attributedString = try! NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
    
    let regex = try! NSRegularExpression(pattern: #"^\s*\d+\."#, options: .anchorsMatchLines)
    let range = NSRange(location: 0, length: attributedString.length)
    regex.enumerateMatches(in: attributedString.string, range: range) { result, _, _ in
        guard let range = result?.range else { return }
        attributedString.addAttribute(.foregroundColor, value: UIColor.red, range: range)
    }
    
    label.attributedText = attributedString
    

    If you know your CSS, you might be inclined to add a coloring via the <style> for ol:before, but that does not appear to work. (If you’re not up on your CSS and didn’t follow what I said, just ignore it, as it doesn’t work, anyway.)

    Anyway, if you go through all of that work, that yields:

    enter image description here