How to make text stroke in SwiftUI?

I find another trick to create stroke, but it only works if your desired stroke width is not more than 1

Text("Hello World")
   .shadow(color: .black, radius: 1)

I used shadow, but make sure the radius is just 1, to get the same efffect


I don't think there's a way for doing that "out of the box".
So far (beta 5) we can apply strokes to Shapes only.

For example:

struct SomeView: View {
    var body: some View {
        Circle().stroke(Color.red)
    }
}

But again that isn’t available for Text.

UIViewRepresentable

Another approach would be to use the good ol' UIKit \ NSAttributedString with SwiftUI via UIViewRepresentable.

Like so:

import SwiftUI
import UIKit

struct SomeView: View {
    var body: some View {
        StrokeTextLabel()
    }
}

struct StrokeTextLabel: UIViewRepresentable {
    func makeUIView(context: Context) -> UILabel {
        let attributedStringParagraphStyle = NSMutableParagraphStyle()
        attributedStringParagraphStyle.alignment = NSTextAlignment.center
        let attributedString = NSAttributedString(
            string: "Classic",
            attributes:[
                NSAttributedString.Key.paragraphStyle: attributedStringParagraphStyle,
                NSAttributedString.Key.strokeWidth: 3.0,
                NSAttributedString.Key.foregroundColor: UIColor.black,
                NSAttributedString.Key.strokeColor: UIColor.black,
                NSAttributedString.Key.font: UIFont(name:"Helvetica", size:30.0)!
            ]
        )

        let strokeLabel = UILabel(frame: CGRect.zero)
        strokeLabel.attributedText = attributedString
        strokeLabel.backgroundColor = UIColor.clear
        strokeLabel.sizeToFit()
        strokeLabel.center = CGPoint.init(x: 0.0, y: 0.0)
        return strokeLabel
    }

    func updateUIView(_ uiView: UILabel, context: Context) {}
}

#if DEBUG
struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView()
    }
}
#endif

Result

result

Of course you have to tweak the attributes (size, font, color, etc) of the NSAttributedString to generate the desired output. For that I would recommend the Visual Attributed String macOS app.


Here is a 100% SwiftUI solution. Not perfect, but it works and it gives you full SwiftUI control of the resulting view.

enter image description here

import SwiftUI

struct SomeView: View {
    var body: some View {
        StrokeText(text: "Sample Text", width: 0.5, color: .red)
            .foregroundColor(.black)
            .font(.system(size: 12, weight: .bold))

    }
}

struct StrokeText: View {
    let text: String
    let width: CGFloat
    let color: Color

    var body: some View {
        ZStack{
            ZStack{
                Text(text).offset(x:  width, y:  width)
                Text(text).offset(x: -width, y: -width)
                Text(text).offset(x: -width, y:  width)
                Text(text).offset(x:  width, y: -width)
            }
            .foregroundColor(color)
            Text(text)
        }
    }
}

I suggest using bold weight. It works better with reasonably sized fonts and stroke widths. For larger sizes, you may have to add Text offsets in more angles to cover the area.


You can do this with SwiftFX

import SwiftUI
import SwiftFX

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
            .fxEdge()
    }
}

Here's the Swift Package:

.package(url: "https://github.com/hexagons/SwiftFX.git", from: "0.1.0")

Setup instructions here.