Draw circle behind particular characters of UILabel

Viewed 911

I am trying to draw circle behind particular parts of UILabel characters without having to use several labels or recompute frames.

I know that I can insert an image into UILabel using attributed text but I want the circle to stand behind the numbers (from 1 to 9). I don't want to store images from 1 to 9. I also cannot find any pod achieving this.

    let fullText = NSMutableAttributedString()

    let imageAttachment = NSTextAttachment()
    imageAttachment.image = UIImage(named: "\(number)_\(color == .yellow ? "yellow" : "gray")")
    let imageString = NSAttributedString(attachment: imageAttachment)
    let endString = NSAttributedString("nouveaux")

    fullString.append(imageString)
    fullString.append(endString)

    mainLabel.attributedText = fullString

enter image description here

EDIT

I want to draw circle behind each digit of a string. I would like it to be a generic tool if possible, some kind of parser that returns an attributed string if possible, a unique UIView if not. Another use case is "4 messages | chat 2" (4 being yellow, 2 being gray)

2 Answers

I don't understand why you don't just use a utility function that draws the digit-in-a-circle in real time. That way, you can have any digit font, circle size, digit color, and circle color that you like. For example:

func circleAroundDigit(_ num:Int, circleColor:UIColor,
                       digitColor:UIColor, diameter:CGFloat,
                       font:UIFont) -> UIImage {
    precondition((0...9).contains(num), "digit is not a digit")
    let p = NSMutableParagraphStyle()
    p.alignment = .center
    let s = NSAttributedString(string: String(num), attributes:
        [.font:font, .foregroundColor:digitColor, .paragraphStyle:p])
    let r = UIGraphicsImageRenderer(size: CGSize(width:diameter, height:diameter))
    return r.image {con in
        circleColor.setFill()
        con.cgContext.fillEllipse(in:
            CGRect(x: 0, y: 0, width: diameter, height: diameter))
        s.draw(in: CGRect(x: 0, y: diameter / 2 - font.lineHeight / 2,
                          width: diameter, height: diameter))
    }
}

Here's how to use it:

let im = circleAroundDigit(3, circleColor: .yellow, 
    digitColor: .white, diameter: 30, font:UIFont(name: "GillSans", size: 20)!)

Here's the resulting image; note, though, that every aspect of this can be tweaked just by calling the function differently:

enter image description here

Okay, so now you've got an image. You say you already know how to insert an image inline into an attributed string and display that as part of the label, so I won't explain how to do that:

enter image description here

This is pretty straightforward using a UIStackView, setting the corner radius of the coloured view's layer…

result…

or with 2 stack views in an outer stack view≥

result…

Related