Lined Notebook

UILabel size를 Text size에 맞추는 방법(혹은 그 반대)

by 사슴비행기

Label의 text 길이가 길어지면

text를 화면에 다 보이게 하기 위한 방법이

있는지 알아보게 될 것이다

 

나는 custom popup view를 만드는 과정에서

text가 길어지면 popup view의 크기를

커지게 해야 하는 상황이라서

이 기능을 좀 더 자세히 살펴보게 되었다

 

그래서 오늘은 일단 화면 크기 기준으로

한 줄짜리의 text의 Label 사이즈를 정하는 방법

한 줄 뿐만 아니라 여러 줄짜리 text를 가진

Label의 size를 정하는 방법에 대해서

공부하고 실습하고 기록해보려고 한다.

 

Apple문서 해석하고 내 견해 적고...

여러 실험을 해보면서 글이 너무 길어졌다..

그래서 추후에 요약본 글을 따로 쓰려고 한다;;

 

목차

1. 한 줄짜리의 짧은 텍스트

sizeToFit()

intrinsicContentSize

   

2. 한 줄 & 여러 줄 텍스트 둘 다 가능

sizeThatFits(_:) → 추천

adjustFontSizeToFitWidth

ceil()


1. 한 줄짜리의 짧은 텍스트

화면 크기를 기준으로

한 줄을 넘지 않는 텍스트를 가진 UILabel의

size를 정하는 방법들은 여러 개가 있다.

2. 한 줄 & 여러 줄 텍스트 둘 다 기능

에서 살펴볼 것들도 모두

한 줄이 가능한 방법이라서

여기서는 한 줄만 가능한 것들만 볼 것이다

 

이해가 쉽도록 Playground를 이용해서

실습을 하면서 글을 쓸 예정인데,

그래서 그전에 아래와 같이

view와 textLabel을 먼저 만들어 놓고

시작할 것이다.

 

view의 크기는 너무 크면 상대적으로 Label이

너무 작아져서 임의로 줄였고,

보기 쉽게 view와 label의 배경색을 주었다.

 

 

let view: UIView = {
    let v = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width/2, height: UIScreen.main.bounds.height/4))
    v.backgroundColor = .lightGray
    return v
}()

var testLabel: UILabel = {
    let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 30, height: 30)))
    label.backgroundColor = .green
    return label
}()

view.addSubview(testLabel)

testLabel.text = "신데렐라는 어려서 부모님을 잃고요,"

view

 

 

위의 코드를 작성하고

마지막 줄에서 실행하면 아래 사진과 같이

잘려버린 UILabel을 확인할 수 있다.

 

 

text가 잘려버린 UILabel

 


 

sizeToFit()

extension UIView {
	//...
    open func sizeToFit()
}

 

이 함수는 UIView의 확장으로 선언되어 있다

그리고 UILabel은 UIView를 상속받았다

 

apple 문서의 sizeToFit() 함수

 

: 수신기 보기가 하위 보기를 둘러싸도록 크기를 조정하고 이동합니다.

= 이 함수를 사용한 라벨의 크기를 Text를 둘러싸도록 조정하고 이동한다.

라고 할 수 있겠다.

 

이 함수를 예제에 맞춰 사용하면 아래와 같다.

그리고 어떻게 나오는지 확인해보면,

Text크기에 맞춰서 Label의 크기가

늘어난 걸 알 수 있다.

 

testLabel.sizeToFit()

view //playground에서 view의 최종 결과를 확인하기 위함

 

그리고 이 함수를 긴 Text를 가진

UILabel에 사용하면 이상한 결과를 얻을 수 있다.

 

일단 Text에 따라서 여러 줄을 가질 수 있도록

label의 속성 중에 numberOfLines를 바꿔주고

Text를 더 길게 바꾼 뒤 실행해보면

Lable의 크기가 상하로 늘어난 걸 볼 수 있다.

(심지어 잘려 있다)

 

label.numberOfLines = 0
testLabel.text = "신데렐라는 어려서 부모님을 잃고요, 계모와 언니들에게 괴롭힘을 당했더래요~"

 

Apple 문서의 문구를 보면 힌트를 얻을 수 있는데,

이 함수를 사용한 라벨의 크기를 Text를 둘러싸도록 조정하고 이동한다.

 

Text를 둘러싸도록 조정하긴 하는데,

그게 가로 일지 세로 일지는 알려주지 않았다.

 

예제를 실습해보니

기본적으로 line이 계속 늘어날 수 있는 상태이면

(numberOfLines속성이 0일 때를 말함)

일단 frame은 정해져 있고

줄 수는 늘어날 수 있으니

늘릴 수 있는 걸 먼저 늘리는 느낌적인 느낌이다.

 


 

intrinsicContentSize

extension UIView {
	//...
    @available(iOS 6.0, *)
    open var intrinsicContentSize: CGSize { get }
    //...
}

 

마찬가지로 UIView에 선언되었다.

이 프로퍼티는 get only다.

 

apple 문서의 intrinsicContentSize 프로퍼티

: 뷰 자신의 프로퍼티들만 고려한 수신 뷰의 자연 크기.

 

이해가 잘 안 가서 세부내용을 뜯어보면...

 

Custom View는 일반적으로 Layout System이 인식하지 못하는 내용을 표시한다.

이 속성을 설정하면 Custom View가 그것의 content에 따라 어떤 사이즈를 원하는지 시스템과 소통할 수 있도록 허용한다.

이 고유한 사이즈는 그 content frame과 독립되어야만 한다. 왜냐하면 예를 들어 변경된 높이를 기준으로 변경된 너비를 레이아웃 시스템에 동적으로 전달할 방법이 없기 때문이다.

 

음... 뭔 뜻인고 한참 고민하니...

우리가 만든 label을 custom view라고

생각하면 될 것 같고,

text 길이가 늘어났을 때

우리가 아무런 작업을 하지 않으면,

label은 변경된 text frame을 알지 못한다.

 

그래서 우리가 그토록 열심히

안에 있는 내용에 따라 그걸 띄우고 있는

view 혹은 label들의 크기를

변경하려고 하는 것...

 

문서에 따르면

이러한 상황이 당연하다고 하는 건데

왜냐면 그것들은 서로 동적으로

자기 사이즈가 변경됐다고

소통할 방법이 없기 때문이다.

 

근데 이 intrinsicContentSize 속성을 사용하면

그 소통을 할 수 있도록 한다는 건데,

get only 속성이었으니,

이 속성으로 받아온 size를

label에 설정하면 된다는 말인 것 같다...

 

그리고 이 intrinsicContentSize 속성을 사용한

view의 안에 있는 프로퍼티만 고려해서

이 view가 가져야 할 크기를 반환한다는 것 같다..

 

틀린 해석이라면 알려주세요...

let newSize = testLabel.intrinsicContentSize
testLabel.frame.size = newSize

view

 

아무튼, 그래서 이렇게 size를 받아와서

label에 설정해주면 된다

 

 

하지만 이것도 여러 줄의 text에는 사용하기 힘든데

label 자신의 프로퍼티를 고려해서

label 자신의 크기를 반환하기 때문에

이 label이 어디에 어떻게 쓰일지는

알바 아니라는 것 같다.

 

label.numberOfLines = 0
testLabel.text = "신데렐라는 어려서 부모님을 잃고요, 계모와 언니들에게 괴롭힘을 당했더래요~"

 

혹시나 해서

view의 크기도 해당 속성을 사용해서 바꿔봤는데

너비와 높이가 -1이 나오더라 ㅋㅋ..

 

let newViewSize = view.intrinsicContentSize //{w -1, h -1}

view에 intrinsicContentSize를 설정한 결과..

뭐지 싶어서 찾아보니,

모든 뷰가 intrinsic content size를

가지는 것이 아니라고 한다...

UIView Intrinsic content size를 가지지 않는다.
UISlider 너비만 Intrinsic content size로 정의한다.
UILabel
UIButton
UISwitch
높이와 너비 모두 Intrinsic content size로 정의한다.
UITextField
UIImageView
Intrinsic content size가 상황에 따라 다르다.(vary)

해당 내용을 설명하는 글 ▼

 

Intrinsic Content Size를 알아보자 (Content Hugging & Compression Resistance)

Intrinsic Content Size

hyunsikwon.github.io


2. 한 줄, 여러 줄 텍스트 둘 다 가능

 

이제 한 줄이던 여러 줄이던

다 가능한 방법을 알아볼 것이다.

여기에서는 위에서 사용한 intrinsicContentSize를

응용해서 쓰는 방법도 있다.

상황에 맞게 쓰면 될 것 같다.

 


 

sizeThatFits(_:) 함수

extension UIView {
	//...
	open func sizeThatFits(_ size: CGSize) -> CGSize
	//...
}

 

이 함수도 UIView의 확장으로 선언되어 있다

그리고 CGSize를 반환하는 함수이다.

 

apple 문서의 sizeThatFits(_:) 함수

: 지정한 크기에 가장 적합한 크기를 계산하여 반환하도록 뷰에 요청합니다.

: 그 뷰에 가장 적합한 크기를 계산해야 하는 크기입니다.

: 수신기의 하위 보기에 맞는 새 크기입니다.

 

그러니깐

파라미터로 크기를 계산해야 하는 Size를 넣고

리턴 값은 파라미터로 받은 하위 뷰에 맞는 크기다.

 

음.. 좀 더 쉽게 말하면

파라미터로 넣은 사이즈에 가장 잘 맞게,

이 함수를 호출한 객체의 사이즈를 리턴해 준다는 것.

 

그런데 이 함수는 한 줄인 경우와

여러 줄인 경우에

파라미터로 넣어야 하는 값이 다르다.

일단 예제를 보면,

 

let newSize = testLabel.sizeThatFits(testLabel.frame.size) //1
newSize = testLabel.sizeThatFits( CGSize(width: testLabel.frame.width, height: CGFloat.greatestFiniteMagnitude)) //2
newSize = testLabel.sizeThatFits(view.frame.size) //3

testLabel.frame.size = newSize
view

 

파라미터로 넣을 수 있는 것들이 정말 많다

1번은 testLabel의 사이즈를 주었다.

2번은 다른 사람들의 코드에서

가장 많이 사용되는 파라미터였고

3번은 내가 문서를 읽어보고

나한텐 이게 더 나을 것 같아서 넣은 파라미터다.

 

먼저, 다른 사람들의 코드를 살펴보면 height를

CGFloat.greatestFiniteMagnitude

이렇게 넣었는데,

Float의 최댓값을 넣겠다는 것이다.

FLT_MAX라고도 하며,

그 값은 3.402823466e+38F이다.

그러니까 높이를 엄청~~~~ 많이 준 것이다.

 

일단 짧은 text는 세 파라미터 모두

같은 결과를 보여주었다.

아마도 문서에서

"가장 적합한 크기를 계산하여 반환"

이라는 문구를 보면,

Label의 text까지 고려해서

가장 적합한 크기를 주는 것 같다.

 

1번 파라미터
2번 파라미터
3번 파라미터

 

문제는 여러 줄일 경우인데,

 

label.numberOfLines = 0
testLabel.text = "신데렐라는 어려서 부모님을 잃고요, 계모와 언니들에게 괴롭힘을 당했더래요~"

 

이렇게 코드를 추가하고 실행해 보면,

좀 다른 결과물을 보여준다.

일단 내 예상이 맞다면,

numberOfLines가 우선시되어서,

줄 수를 계속 추가할 수 있으면,

일단 그것 먼저 실행한다.

2번 파라미터도 height를 엄~~~~ 청

많이 주어서 계속 줄 수를 늘린 것이다.

 

1번 파라미터
2번 파라미터
3번 파라미터

근데 3번 파라미터는

height가 view의 height로 고정이 되어 있으니

줄 수를 늘리다 보면

글자가 안 보인다는 것을 캐치하고는

해당 파라미터에서 가장 적합한

크기로 리턴 값을 준 것이다.

응..? 근데 나는 view의 가로는 맞추되, 안에 스크롤이 있어서 height는 엄청 커도 상관없어요!

이런 경우라면,

 

let newSize = testLabel.sizeThatFits(CGSize(width: view.frame.width, height: CGFloat.greatestFiniteMagnitude)) //4

 

파라미터로 넣을 사이즈를 이렇게 주면 되겠다.

 

4번 파라미터

그러면 이렇게 나온다.

아, 그리고 여기서

왜 label이 view의 가로에 딱 안 맞죠?!

 

라고 생각된다면,

label의 lineBreakMode 속성을

바꾸어주면 된다.

 

label.lineBreakMode = .byCharWrapping

byCharWrapping

 


adjustFontSizeToFitWidth

 

이건 이전에도 많이 사용했던 속성인데,

autolayout에도 있는 속성 값이다.

 

storyboard에 있는 UILabel의 Autoshrink에 마우스를 가져다 놓으면 뜨는 설명

@available(iOS 2.0, *)
open class UILabel : UIView, NSCoding, UIContentSizeCategoryAdjusting {
	//...
    // these next 3 properties allow the label to be autosized to fit a certain width by scaling the font size(s) by a scaling factor >= the minimum scaling factor
    // and to specify how the text baseline moves when it needs to shrink the font.
    
    open var adjustsFontSizeToFitWidth: Bool // default is NO
    //...
}

 

이 속성은 UILabel의 확장으로 선언되어 있다.

 

: 레이블의 경계 사각형에 제목 문자열을 맞추기 위해 레이블에서 텍스트의 글꼴 크기를 줄일지 여부를 결정하는 부울 값입니다.

 

말 그대로 Label의 기존 사이즈에

text를 다 보이게 하기 위해

text의 폰트 사이즈를 바꾼다.

 

testLabel.adjustsFontSizeToFitWidth = true
view

 

잘 안 보이지만,

텍스트가 아주 작게 보이긴 한다...ㅋㅋㅋㅋ

한 줄짜리 text가 아니어도

label 크게에 text를 맞추는 것이기 때문에

 

 

요로코롬 다 들어간다.. ㅋㅋ..

사용하기 나름... 괜찮을지도 모른다....ㅎ

 


 

ceil() 함수

마지막으로 ceil() 함수를 써볼 것이다.

이 함수에 대해서는 이전에 포스팅한 적이 있다.

 

Swift 소수점 다루기, 소수점 제거하기, 소수점 제거 함수

https://blog.naver.com/muelan84/222523154704 소수점 제거 함수 오늘은 소수점 제거 함수에 대해서 적어볼게요 원글 링크 : http://seorenn.blogspot.com/2018/02/ceil-flo... blog.naver.com 여기저기 흩어져..

doorganizedcoding.tistory.com

 

ceil()은 소수점 뒤에 있는 숫자를

정수 1로 포함시켜주는 것이다.

 

그래서 이걸 어떻게 써먹느냐면,

위에서 다뤘던 intrinsicContentSize 값을

이용해서 사용할 것이다.

 

testLabel.numberOfLines = 0
testLabel.lineBreakMode = .byCharWrapping
testLabel.text = "신데렐라는 어려서 부모님을 잃고요, 계모와 언니들에게 괴롭힘을 당했더래요~"

let newSize = testLabel.intrinsicContentSize
testLabel.frame.size = newSize

if testLabel.frame.width > view.frame.width {
    let shareOfDivision = ceil((testLabel.frame.width / view.frame.width))
    let newHeight = testLabel.frame.height * shareOfDivision
    testLabel.frame.size = CGSize(width: view.frame.width, height: newHeight)
}

view

 

 

즉, 실제 label의 width가 view의 width보다

몇 배 긴가에 따라 heigth에 곱해주는 것이다.

 

이렇게 하면 한 줄 일 때도 여러 줄 일 때도

사용할 수 있지만, 기본 제공되는

sizeThatFits(_:) 함수가 있는데

굳이 사용할 필요는 없어 보인다..

 

그저 sizeThatFits(_:) 함수를 모르는 때에

야매로 쓰는 방법이라고 생각하면 될 것 같다.

 

한 줄
여러 줄

그리고 이 글을 쓸 때 참고한 블로그 글 첨부한다.

 

iOS - UILabel 크기를 텍스트에 맞추기

iOS의 UILabel의 크기를 text에 알맞게 조정하는 방법에 대해 공유합니다.

kangraemin.github.io

 

 

그냥 대충 알고 쓰면 해당 방법이 안 될 때

"이게 왜 안되지..?"

라는 생각이 들면서 안 해도 되는

삽질을 할 가능성이 높다..

 

그러니 내 방법으로 잘 공부해 두고

잘 꺼내 쓰면 좋은 것 같다..

 

다음 포스팅은 apple 기기의 설정(setting)에서

손쉬운 사용의

디스플레이 및 텍스트 크기에서

더 큰 텍스트 등으로 글씨 크기를 바꿀 때

이미 설정될 label의 크기를

dynamic하게 바꾸는 방법을 알아보려고 한다.

(그래 마저... 우리에겐...)

(그런 변수도 있었어.....)

블로그의 정보

Beautiful Coding

사슴비행기

활동하기