Text Size 구하기

Label 과 TextView TextField 등을 통한 UI를 작업할 때 보통은 오토레이아웃으로 처리를 하지만, 가끔은 텍스트를 통해서 직접 사이즈를 구해 작업을 해야 할 때가 있다. 구글링을 해보면 boundingRect(with:options:attributes:context:)size(withAttributes:) 이 두가지 메서드를 자주 사용하는 것을 확인할 수 있었고, 두 메서드를 제대로 확인하고 비교하고자 해당 포스트를 작성하게 되었다.

# NSString.boundingRect(with:options:attributes:context:)

Calculates and returns the bounding rect for the receiver drawn using the given options and display characteristics, within the specified rectangle in the current graphics context.

먼저 boundingRect에 대해서 알아보자. 해당 메서드의 정의는 위와 같이 되어있다. 그렇다면 해당 메서드의 필요한 파라미터부터 살펴보자.

with size : 텍스트가 그려지려는 박스의 크기

options : String 에 대한 드로잉옵션

attributes : NSAttributedString에 대한 옵션과 동일하다. 단, NSString 의 경우에는 문자열 내의 범위가 아닌 문자열 전체에 적용 된다는 점이 다르다.

context : 수신자에 사용할 드로잉 컨텍스트

 

특정한 사각형 내부에서 옵션 들과 표시 특성들을 활용하여 경계 사각형을 계산하고 반환을 한다. 예를 들어서 한줄이 넘어가는 텍스트가 있다고 하자, 해당 텍스트는 특정한 뷰의 박스 내부에서 여러 개의 줄로 나뉘어 질 것이다. 그렇다면 해당 박스와 옵션들을 토대로 텍스트가 표현될 사이즈를 계산할 수 있는 것이다.

 

이번에는 Discussion을 살펴보자. 여러 줄이 있는 텍스트의 사이즈를 정확하게 알고 싶다면, parameter의 옵션에 usersLineFragmentOrigin을 전달하면 된다. 또한 계산된 값은 소수점으로 떨어진 값이다. 따라서 뷰에 그려지는 값을 알고 싶다면 ceil function을 이용해서 가까운 integer값을 찾아야 한다. 해당 메서드는 string 상형문자의 실제 경계를 나타낸다. 예를 들어 공백과 같은 상형문자는 layout을 겹치도록 할 수 있고, 이러한 경우에는 주어진 size의 width를 넘어갈 수 있음을 기억해야 한다.

# NSString.size(withAttributes:) 

Returns the bounding box size the receiver occupies when drawn with the given attributes.

size의 정의는 위와 같이 되어 있다. 해당 메서드에 필요한 파라미터는 boundingRect 의 attributes 와 동일하므로 설명은 생략하겠다. NSAttributedString에 적용되는 특성 들이며 string 전체에 적용이 된다. 그렇다면 해당 메서드의 Discussion은 어떨까? boudingRect보다 훨씬 더 간단하게 되어있다. 소수점으로 계산된 값이 리턴되고 view에 그려지는 값을 알고 싶다면 ceil을 이용해서 integer를 찾으라는 내용이다.

# boudingRect VS size

둘의 차이를 살펴보면 생각보다 간단하다. 만약 크기를 구하고자 하는 텍스트의 줄 수가 하나라면 size를 사용 하는 것이 간편할 것이고, 여러 줄의 텍스트의 크기를 알고 싶다면 boundingRect를 사용하는 것이 적절할 것이다.

 

하나의 팁을 전수 하자면 만약 width는 일정하고 height이 궁금한 경우가 있다고 하자. 이때 width에 고정된 값을 넣고, height에는 CGFloat.magnitudgreatestFiniteMagnitude(CGFloat가 가질 수 있는 최대 값)을 넣는다면 박스의 사이즈를 고민하지 않고 쉽게 값을 구할 수 있다. 다음과 같이 말이다.

1
2
3
4
5
let newText = "hello world hello world hello world"
NSString(string: newText).boundingRect(with: CGSize(width: 50.0, height: CGFloat.greatestFiniteMagnitude),
                                        options: .usesLineFragmentOrigin,
                                        attributes: [.font: label.font!], 
                                        context: nil)
cs

# One More

만약 중간에 특정한 부분만 폰트 혹은 값이 다르다면 어떻게 해야할까? 예를 들어서, HELLO WORLD 라는 텍스트의 크기를 구하고자 할 때, HELLO 의 font size는 16 이지만 WORLD 의 font size 는 12 라고 하자. 위 메서드들의 파라미터 중에서 attributes에 대한 설명을 살펴보면 String 전체에 적용되는 특징이라고 나와 있으며, 조금 더 살펴보면 NSAttributedString 과는 다르다고 나와있다. 따라서 해당 경우에 특징이 전체로 적용되는 NSString이 아닌 NSAttributedString.boudingRect ( 혹은 size ) 를 사용하는 것이 적절하다.

REFERENCE

[Document] size

[Document] boundingRect

'iOS & Swift' 카테고리의 다른 글

Responder Chain ( 앱은 유저의 인터렉션을 어떻게 처리하는가 ? )  (0) 2021.03.18
Reducing Dynamic Dispatch ( 성능향상 )  (0) 2021.01.24
Encoding 정복하기  (0) 2020.11.23
Decoding 정복하기  (2) 2020.11.14
Codable  (0) 2020.10.25

+ Recent posts