카테고리 없음

[SwiftUI] 테두리 있는 Text 그리기(Outline Text, Stroke Text)

냄수 2024. 5. 25. 16:30
반응형

결과물 이미지부터 볼게요

SwiftUI로 이런 테두리가 있는 Text를 만들어볼거에요!

 

iOS 17.0기준으로 아직 SwiftUI 모디파이어라던가 뷰 타입에서 Outline에 색을 칠할 수 있는 방법은 따로없어서

커스텀으로 만들어줬어요

 

메커니즘은 텍스트 2개를 중첩을해서 뒷텍스트는 테두리처럼, 앞에꺼는 폰트색처럼 사용하려고해요

만약 SwiftUI의 Text를 2개를 중첩한다면 좀더 복잡하고 계산할게 많아져요

또한

SwiftUI에서 사용가능한  AttributedString는 테두리가 먹히질 않아서 실패했어요

 

따라서

UIKit에 있는 UILabel을 사용할거에요

NSAttributedString을 이용해서 테두리를 적용시켜줄건데

이때 속성으로 strokeColor와 foregroundColor 둘다 적용할 수 가 없어요

(foregroundColor를 적용하나 strokeColor를 적용하나 똑같이 폰트색이 적용됩니다

하지만 명시적으로 테두리색 느낌을 주기위해 stroke를 사용했습니다)

해보시면 알겠지만 둘중 하나만 적용됩니다!

 

 

테두리가될 뷰를 먼저 만들어봅시다!

// SwiftUI로는 AttributeString적용시 text stroke속성 적용불가능
struct StrokeText: UIViewRepresentable {
    let text: String
    let font: UIFont
    let strokeColor: UIColor
    let strokeWidth: CGFloat
    
    func makeUIView(context: Context) -> UILabel {
        let label: UILabel = UILabel()
        let attribute: [NSAttributedString.Key: Any] = [
            .strokeColor: strokeColor,
            .strokeWidth: strokeWidth,
            .font: font
        ]
        label.attributedText = NSAttributedString(string: text, attributes: attribute)
        label.sizeToFit()
        label.textAlignment = .center
        return label
    }
    
    func updateUIView(_ uiView: UILabel, context: Context) {
        let attribute: [NSAttributedString.Key: Any] = [
            .strokeColor: strokeColor,
            .strokeWidth: strokeWidth,
            .font: font
        ]
        uiView.attributedText = NSAttributedString(string: text, attributes: attribute)
        uiView.textAlignment = .center
        uiView.sizeToFit()
    }
}

속성에 필요한것들을 넣어주고... 

 

 

 

그다음으로는 위에서만든 테두리뷰에 SwiftUI의 Text를 위에 얹어서 완성시켜볼게요

struct StrokeTextView: View {
    let text: String
    let textColor: Color
    let font: PretendardFont
    let fontSize: CGFloat
    let strokeColor: Color
    let strokeWidth: CGFloat
    
    private var storkeUIColor: UIColor { UIColor(strokeColor) }
    
    init(
        text: String,
        textColor: Color,
        font: PretendardFont,
        fontSize: CGFloat,
        strokeColor: Color,
        strokeWidth: CGFloat = 15
    ) {
        self.text = text
        self.textColor = textColor
        self.font = font
        self.fontSize = fontSize
        self.strokeColor = strokeColor
        self.strokeWidth = strokeWidth
    }
    
    var body: some View {
        StrokeText(
            text: text,
            font: UIFont(name: font.rawValue, size: fontSize)!,
            strokeColor: storkeUIColor,
            strokeWidth: strokeWidth
        )
        .overlay {
            Text(text)
                .font(.custom(font.rawValue, size: fontSize))
                .foregroundStyle(textColor)
        }
    }
}

 

 

사용할땐 만들어두면

이렇게 쉽게 적용가능합니다!

#Preview {
    StrokeTextView(
        text: "NSiOS",
        textColor: .purple,
        font: .bold,
        fontSize: 50,
        strokeColor: .black,
        strokeWidth: 12
    )
}

 

이쁘네요!

반응형