I want to draw an outline around the text of UILabel
like this:
I tried using attributed text but there is no attribute for rendering border around text. Only underline is available. I also tried rendering html using attributed text but that didn't help either:
let htmlLabelText = String(format: "<html><body><span style='color:blue; border: 1.5px solid #55DF49; border-radius: 50px;'>%@</span></body></html>", labelText)
var attributedString = NSMutableAttributedString()
guard let stringData = data(using: .unicode) else { return NSMutableAttributedString() }
do {
attributedString = try NSMutableAttributedString(
data: stringData,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil
)
} catch {}
I checked other post but none of them helped.
The problem is quite hard to solve for UILabel, because you have no direct access to NSLayoutManager, which is key for my solution.
I have created IBDesignable UILabel subclass LineHighlightedLabel, which can do the job. The visual is not quite the same as image you provided but you can get there.
Important part is to set text to UILabel as NSAttributedString, not just plain text.
@IBDesignable
public class LineHighlightedLabel: UILabel {
public override func draw(_ rect: CGRect) {
let layoutManager = NSLayoutManager()
let textStorage = NSTextStorage.init(attributedString: attributedText!)
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer.init(size: bounds.size)
textContainer.lineFragmentPadding = 0
textContainer.maximumNumberOfLines = numberOfLines
textContainer.lineBreakMode = lineBreakMode
layoutManager.addTextContainer(textContainer)
layoutManager.enumerateLineFragments(forGlyphRange: NSMakeRange(0, textStorage.length)) { (rect, usedRect, textContainer, glyphRange, bool) in
let lineRect = CGRect(x: usedRect.origin.x, y: usedRect.origin.y + 1, width: usedRect.size.width, height: usedRect.size.height - 2)
UIColor.green.setStroke()
let lineRectPath = UIBezierPath(roundedRect: lineRect, cornerRadius: 5)
lineRectPath.lineWidth = 0.5
lineRectPath.stroke()
}
super.drawText(in: rect)
}
public override func layoutSubviews() {
super.layoutSubviews()
setNeedsDisplay()
}
}
LineHighlightedLabel is providing nice preview in interface builder, you can play with values easily.