Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - SwiftUI] 한글 개행 처리 방법, 한글 글자 단위 개행 방법 (linebreak, byCharWrapping 적용 방법, byWordWrapping) 본문

iOS 응용 (SwiftUI)

[iOS - SwiftUI] 한글 개행 처리 방법, 한글 글자 단위 개행 방법 (linebreak, byCharWrapping 적용 방법, byWordWrapping)

jake-kim 2025. 4. 23. 01:28

Text 컴포넌트의 디폴트 개행 처리 방식

  • SwiftUI의 Text의 디폴트 개행 방식은 띄어쓰기 단위로 개행
struct ContentView: View {
    var body: some View {
        VStack {
            // 문구 출처: https://ko.wikipedia.org/wiki/%EC%95%A0%ED%94%8C
            Text("애플(영어: Apple Inc.)은 미국 캘리포니아의 아이폰, 아이패드, 애플 워치, 에어팟, 아이맥, 맥북, 맥 스튜디오와 맥 프로, 홈팟, 비전 프로, 에어태그 등의 하드웨어와 그 제품들의 iOS, iPadOS, Watch OS, macOS, Vision OS, TV OS 등의 소프트웨어를 설계, 디자인하는 기업이다. 2011년부터 팀 쿡이 CEO를 맡고 있다. 또한 그 소프트웨어에 애플 앱 스토어, 뮤직, 뉴스, 아케이드, tv, 피트니스, 페이, 저장 클라우드 등의 서비스를 제공한다.")
        }
    }
}

띄어쓰기 단위로, 길이가 길땐 다음 행에 문구를 배치

  • 이것은 UIKit의 UILabel에 lineBreakMode 디폴트 값인 `byWordWrapping`와 동일
    • (UILabel의 lineBreakMode 참고)
=public enum NSLineBreakMode : Int, @unchecked Sendable {   
    case byWordWrapping = 0 // Wrap at word boundaries, default

    case byCharWrapping = 1 // Wrap at character boundaries

    case byClipping = 2 // Simply clip

    case byTruncatingHead = 3 // Truncate at head of line: "...wxyz"

    case byTruncatingTail = 4 // Truncate at tail of line: "abcd..."

    case byTruncatingMiddle = 5 // Truncate middle of line:  "ab...yz"
}
  • 여기서 byCharWrapping같이 문자 하나를 기준으로 개행을 하고자 한다면 SwiftUI에서는 해당 옵션이 없기 때문에 별도 구현 필요

(byCharWrapping)

UILabel의 byCharWrapping 옵션

SwiftUI에서 byCharWrapping 구현 방법

  • UIViewRepresentable을 활용하여 UILabel을 SwiftUI에서도 쓸 수 있게끔 만드는 방법이 있지만, 수정양이 많은 단점이 있으므로 다른 방법 사용하기
  • \u{200B} 문자 사용하기
  • \u{200B} 문자 특성상 width가 0인 문자인데, 이 문자들을 기존 문자들 뒤에 삽입
    • 이 문자는 개행을 할 수 있는 기준이 되므로 iOS 내부에서 이 문자를 만났을 때 frame의 width에 도달한다면 바로 개행 시킬 것
    • 곧 기존 문자 바로 뒤에 이 문자가 붙으므로써 개행의 기준이 단어 단위로 바뀐 것
  • extension으로 기존문자들 사이에 이 문자를 삽입
extension String {
    var byCharWrapping: Self {
        map(String.init).joined(separator: "\u{200B}")
    }
}
  • 사용하는쪽에서는 아래 처럼 사용하기만 하면 byCharWrapping 완성
Text(sampleText.byCharWrapping)

SwiftUI에서도 byCharWrapping 적용 완료

  • 전체 코드
import UIKit
import SwiftUI

struct ContentView: View {
    let sampleText = "애플(영어: Apple Inc.)은 미국 캘리포니아의 아이폰, 아이패드, 애플 워치, 에어팟, 아이맥, 맥북, 맥 스튜디오와 맥 프로, 홈팟, 비전 프로, 에어태그 등의 하드웨어와 그 제품들의 iOS, iPadOS, Watch OS, macOS, Vision OS, TV OS 등의 소프트웨어를 설계, 디자인하는 기업이다. 2011년부터 팀 쿡이 CEO를 맡고 있다. 또한 그 소프트웨어에 애플 앱 스토어, 뮤직, 뉴스, 아케이드, tv, 피트니스, 페이, 저장 클라우드 등의 서비스를 제공한다."
    
    var body: some View {
        VStack {
            Text(sampleText.byCharWrapping)
            
            Spacer()
                .frame(height: 30)
            
            LabelView(text: sampleText)
        }
    }
}

extension String {
    var byCharWrapping: Self {
        map(String.init).joined(separator: "\u{200B}")
    }
}

struct LabelView: View {
    var text: String

    @State private var height: CGFloat = .zero

    var body: some View {
        InternalLabelView(text: text, dynamicHeight: $height)
            .frame(minHeight: height)
    }

    struct InternalLabelView: UIViewRepresentable {
        var text: String
        @Binding var dynamicHeight: CGFloat

        func makeUIView(context: Context) -> UILabel {
            let label = UILabel()
            label.numberOfLines = 0
            label.lineBreakMode = .byCharWrapping

            return label
        }

        func updateUIView(_ uiView: UILabel, context: Context) {
            uiView.text = text

            DispatchQueue.main.async {
                dynamicHeight = uiView.sizeThatFits(CGSize(width: uiView.bounds.width, height: CGFloat.greatestFiniteMagnitude)).height
            }
        }
    }
}

#Preview {
    ContentView()
}

* 참고

- https://ko.wikipedia.org/wiki/%EC%95%A0%ED%94%8C

- https://chatgpt.com/c/68049c4f-b2b0-8011-af7e-4e447015bdf0

Comments