본문 바로가기

개발경험

SwiftUI LineBreakStrategy 적용기(UIViewRepresentable)

반응형

올해 2월 SwiftUI를 사용하는 스타트업에 취업 성공하고 바쁘게 지내고 있다

취업 준비를 할 때는 UIKit 과 SwiftUI를 반 반 활용해가며 개발을 진행해갔는데 취업 이후에는 SwiftUI를 주로 사용하고 정말 필요한 경우에 UIKIt 기술을 가져와 사용하고 있다.

 

최근 회사에서 개발을 하면서 삽질을 했던 것들 중 하나가 LineBreakStrategy이다. 

 

SwiftUI에서 Text에 줄바꿈을 하다보면 분명 단어가 더 들어갈 자리가 있음에도 줄바꿈을 하는 경우가 존재했다. 
혹은 한 단어임에도 줄바꿈이 일어나는 경우가 존재했다. 

이 UI는 단순화해서  다음과 같은 코드로 만들어졌다. 

        HStack(alignment: .center) {
            Text("비행기 안의 여행 친구, 스튜어디스")
                .foregroundColor(.white)
                .font(.system(size: 30, weight: .bold))
                .lineLimit(2)
            Spacer()
        }

 

 

이미지를 보면 분명 첫번 째 줄에 "비행기 안의 여행 친구," 까지는 들어갈 것 같지만
이상하게도 줄바꿈이 되어 있었다. 

 

이를 SwiftUI 내에서 해결하고자 엄청 찾았지만 결국 찾지 못하고 

UIKit으로는 있지 않을까 하는 차에 

https://developer.apple.com/documentation/uikit/nsparagraphstyle/linebreakstrategy/3667458-hangulwordpriority

 

hangulWordPriority | Apple Developer Documentation

The text system prohibits breaking between Hangul characters.

developer.apple.com

LineBreakStrategy에 hangulWordPriority를 발견했다. 

LineBreakStrategy란?

텍스트 시스템이 단락을 배치하는 동안 줄을 나누는 방식을 지정하는 상수이다. 

 

public struct LineBreakStrategy : OptionSet, @unchecked Sendable {

        public init(rawValue: UInt)

        
        @available(iOS 9.0, *)
        public static var pushOut: NSParagraphStyle.LineBreakStrategy { get }

        
        @available(iOS 14.0, *)
        public static var hangulWordPriority: NSParagraphStyle.LineBreakStrategy { get }

        
        @available(iOS 14.0, *)
        public static var standard: NSParagraphStyle.LineBreakStrategy { get }
    }

 

3가지가 정의되어 있는데 이 중에서 iOS 14에 새로 생긴 hangulWordPriority를 사용해보았다. 

 

hangulWordPriority?

기존에 있던 문제점인 한글 글자 사이에 분리를 막는다. 

 

 

이제 어떤걸 사용할지 알았으니 SwiftUI에 사용하면 된다. UIKit 기능을 SwiftUI로 가져오기 위해서는 UIViewRepresentable을 사용한다. 

 

struct Title: UIViewRepresentable {
    let title: String
    
    func makeUIView(context: Context) -> UILabel {
        let label = UILabel()
        label.lineBreakStrategy = .hangulWordPriority
        label.numberOfLines = 2
        label.textColor = .white
        label.font = .systemFont(ofSize: 36, weight: .bold)
        return label
    }
    
    func updateUIView(_ uiView: UILabel, context: Context) {
        uiView.text = title
    }
}

이렇게 만들면 SwiftUI에서 UIKit에서의 hangulWordPriority를 사용할 수 있다. 

 

하지만 이러면 UIKit의 UILabel을 SwiftUI에서 레이아웃을 원하는대로 사용하지 못한다..

 

물론 .frame()으로 height를 고정적으로 박아놓으면 상관없겠지만 동적으로 처리를 하기에는 좋은 방법이 아니였다. 

 

현재에는 2가지 문제가 있는데 

1. width를 파악하지 못하고 텍스트가 레이아웃을 넘어가버림

2. 높이가 라벨의 높이만큼 동적으로 바뀌지 않음 

 

1. width를 파악하지 못하고 텍스트가 레이아웃을 넘어가버림

https://developer.apple.com/documentation/uikit/uilabel/1620534-preferredmaxlayoutwidth

 

preferredMaxLayoutWidth | Apple Developer Documentation

The preferred maximum width, in points, for a multiline label.

developer.apple.com

 

이 문제를 해결하기 위해서 "preferredMaxLayoutWidth"를 사용했다. 

UILabel에 preferredMaxLayoutWidth라는 프로퍼티가 있는데 이것은 여러 줄의 라벨에 최대 너비를 지정하는 것이다. 

struct Title: UIViewRepresentable {
    private var preferredMaxLayoutWidth: CGFloat = 0
    let title: String
    
    func makeUIView(context: Context) -> UILabel {
        let label = UILabel()
        label.lineBreakStrategy = .hangulWordPriority
        label.numberOfLines = 2
        label.textColor = .white
        label.font = .systemFont(ofSize: 36, weight: .bold)
        return label
    }
    
    func updateUIView(_ uiView: UILabel, context: Context) {
        uiView.preferredMaxLayoutWidth = preferredMaxLayoutWidth
        uiView.text = title
    }
}

이렇게 만들어 사용하는 시점에 MaxLayoutWidth를 넣어주면 레이아웃이 깨지지 않고 줄바꿈이 잘되는 모습이다. 

하지만 아직 높이가 동적으로 변하지 않고 있다. 

2. 높이가 라벨의 높이만큼 동적으로 바뀌지 않음 

https://developer.apple.com/documentation/swiftui/view/fixedsize()

 

fixedSize() | Apple Developer Documentation

Fixes this view at its ideal size.

developer.apple.com

이 문제를 해결하기 위해서는 fixedSize()라는 인스턴스 메서드를 사용했다. 

이 메서드는 뷰를 이상적인 사이즈로 수정한다. 

 

결과적으로 SwiftUI에서 UIKit 기능을 사용함으로 한글에 맞는 줄바꿈 기능을 사용해보았다 ㅎㅎ

반응형