Home > database >  How to achieve a thick stroked border around text UILabel
How to achieve a thick stroked border around text UILabel

Time:09-30

This is what I am trying to achieve:

enter image description here

Heres a few things I tried:

NSAttributedString

I have tried using NSAttributedString with the below attributes, but there seems to be a bug with text paths in iOS 14

private var attributes: [NSAttributedString.Key: Any] {
    [
        .strokeColor : strokeColor,
        .strokeWidth : -8,
        .foregroundColor : foregroundColor,
        .font: UIFont.systemFont(ofSize: 17, weight: .black)
    ]
}

NSAttributedString

I'd be perfectly fine with this result from NSAttributedString if it didn't have that weird pathing issue with some of the letters.

Draw Text Override

I have also tried to override drawText, but as far as I can tell, I cant find any way of changing the stroke thickness and having it blend together with the next character:

override func drawText(in rect: CGRect) {
    let context = UIGraphicsGetCurrentContext()
    context?.setLineJoin(.round)
    
    context?.setTextDrawingMode(.stroke)
    self.textColor = strokeColor
    super.drawText(in: rect)
    
    context?.setTextDrawingMode(.fill)
    self.textColor = foregroundColor
    super.drawText(in: rect)
    
    layer.shadowColor = UIColor.black.cgColor
    layer.shadowRadius = 2
    layer.shadowOpacity = 0.08
    layer.shadowOffset = .init(width: 0, height: 2)
}

enter image description here

CodePudding user response:

Use this designable class to render labels with the stroke on the storyboard. Most of the fonts I tried look bad (with CGLineJoin.miter), I found the "PingFang TC" font most closely resembles the desired output. Though CGLineJoin.round lineJoin looks fine on most of the font.

@IBDesignable
class StrokeLabel: UILabel {
    @IBInspectable var strokeSize: CGFloat = 0
    @IBInspectable var strokeColor: UIColor = .clear
  
    override func drawText(in rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        let textColor = self.textColor
        context?.setLineWidth(self.strokeSize)
        context?.setLineJoin(CGLineJoin.miter)
        context?.setTextDrawingMode(CGTextDrawingMode.stroke)
        self.textColor = self.strokeColor
        super.drawText(in: rect)
        context?.setTextDrawingMode(.fill)
        self.textColor = textColor
        super.drawText(in: rect)
    }
}

Output: (Check used values in the attribute inspector for reference)

enter image description here

  • Related