iOS 개발 기록

[UIKit] preferredMaxLayoutWidth, IntrinsicContentSize, Priority 본문

UIKit

[UIKit] preferredMaxLayoutWidth, IntrinsicContentSize, Priority

택꽁이 2023. 7. 3. 14:44
728x90

📄

preferredMaxLayoutWidth

  • 여러 줄의 UILabel에 적용될 수 있는 프로퍼티. UILabel최대 너비를 설정한다. 최대 너비를 넘어가는 경우 UILabel은 새로운 줄로 개행하며 높이를 증가시킨다.
  • preferredMaxLayoutWidth를 설정해서 일정한 텍스트 레이아웃을 정렬하거나 적절한 레이아웃을 유지할 수 있다.

  • Storyboard에서는 Desired Width에서 설정할 수 있다 . 이미지에서는 preferredMaxLayoutWidth를 설정했지만 Lines = 1인 상태이기 때문에 멀티라인이 아니므로 아무런 변화가 없다.

  • Lines = 0으로 했을 때에 preferredMaxLayoutWidth가 적용되어 너비에 맞게 개행된걸 확인할 수 있다.

  • 나는 Custom Label을 만들기 위해 코드로 다음과 같이 설정해 사용했다. 다음 코드에서는 text가 입력되어 bounds가 설정될 때에 최대 너비를 width에서 padding을 뺀 값으로 설정한다.
    class CustomLabel: UILabel { 
      // ... 코드들 
      override var bounds: CGRect { 
        didSet { 
          preferredMaxLayoutWidth = bounds.width - (leftInset + rightInset)
        }
      }
    }

IntrinsicContentSize

  • View의 내부 콘텐츠를 자연스럽게 표시하기 위한 최소한의 크기. View에 자체적으로 IntrinsicContentSize를 가지는 View들도, 없는 View들도 있다.
  • 대부분의 View들이 IntrinsicContentSize를 가지고 있지만, UIView는 IntrinsicContentSize가 없다. View의 위치만 잡았을 때에 UILabelIntrinsicContentSize가 있기 때문에 괜찮지만 UIView는 크기를 잡아달라고 에러를 띄운다.

  • IntrinsicContentSize의 유무는 view.IntrinsicContentSize 프로퍼티를 찍어서 확인할 수 있다. 해당 값이 -1이라면 IntrinsicContentSize가 없는 것이다.
    let view = UIView()
    
    print(view.view.intrinsicContentSize) 
    
    // 출력 
    // (-1, -1)

  • 물론 UIView의 경우에도 원한다면 IntrinsicContentSize를 적용할 수 있다.
    class CustomView: UIView { 
      let btn: UIButton = { 
        // 코드
      }()
    	
      override var intrinsicContentSize: CGSize {
        let height = btn.frame.size.height
        let width =  btn.frame.origin.x + btn.frame.size.width
        return CGSize(width: width, height: height)
      }
    }

  • IntrinsicContentSize가 있는 View들은 AutoLayout 적용 시에 우선순위 문제가 발생한다. 해당 문제는 Priority를 조정하여 해결할 수 있다.

invalidateIntrinsicContentSize()

  • IntrinsicContentSize를 무효화한다. 즉 view의 크기에 변화가 있을 때에 invalidateIntrinsicContentSize() 메소드를 호출하여 기존의 IntrinsicContentSize를 무효화하고, 새로운 IntrinsicContentSize를 계산하여 변화된 크기를 적용한다.

Priority

Content Hugging Priority

  • IntrinsicContentSize보다 커지는 것을 허용하지 않는다. → 우선순위가 낮은 뷰의 크기가 늘어난다.
  • 기본값은 250이며, 다음과 같이 코드를 통해서도 설정할 수 있다.
    let spacer: UILabel = {
      let view = UILabel()
      // 가로 방향으로 고유 컨텐츠보다 커지는걸 절대 허용하지 않음.
      view.setContentHuggingPriority(.required, for: .horizontal)
      // 세로 방향으로 우선순위에 따라 고유컨텐츠보다 늘어날 수 있음.
      view.setContentHuggingPriority(.defaultLow, for: .vertical)
      return view
    }()

Content Compression Resistance Priority

  • IntrinsicContentSize보다 작아지는 것을 허용하지 않는다. → 우선순위가 낮은 뷰의 크기가 작아진다.
  • 기본값은 750이며, 다음과 같이 코드를 통해서도 설정할 수 있다.
    let spacer: UILabel = {
      let view = UILabel()
      // 가로 방향으로 고유 컨텐츠보다 줄어드는걸 절대 허용하지 않음.
      view.setContentCompressionResistancePriority(.required, for: .horizontal)
      // 세로 방향으로 우선순위에 따라 고유컨텐츠보다 줄어들 수 있음.
      view.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
      return view
    }()

Reference

invalidateIntrinsicContentSize() | Apple Developer Documentation
Invalidates the view’s intrinsic content size.
https://developer.apple.com/documentation/uikit/uiview/1622457-invalidateintrinsiccontentsize/
[iOS] preferredMaxLayoutWidth, Intrinsic content size, Content hugging priority, content Compression resistance priority
preferredMaxLayoutWidth preferredMaxLayoutWidth 는 multiline label 일 때 영향을 주는 property 로 Label 의 Width 가 42 이상 늘어나지 못함을 명시적으로 Set 할 수 있다. 이상 이므로 글자가 더 들어갈 공간이 없으면 width 가 42 보다 적게 들어갈 수 있다. (Ex. width = 40.5) multiline label 이 아닌경우 아무런 영향을 미치지 못한다. preferredMaxLayoutWidth 를 설정한 채로 Label 에 Text 를 set 하면 intrinsic content size 가 실제 사이즈처럼 나온다.sizeThatFits 와 비교했을 때 intrinsicContentSize 가 월등히 좋다. (다만,..
https://beankhan.tistory.com/41

Uploaded by N2T

'UIKit' 카테고리의 다른 글

[UIKit]UIKit(CollectionView)+Combine  (0) 2023.02.25
[UIKit]Modern Collection View  (0) 2023.02.21
[UIKit]UICollectionViewCompositionalLayout (iOS 13.0 +)  (0) 2023.02.21
[iOS]Scene, Window, View의 개념  (0) 2023.02.15
View의 라이프 사이클  (0) 2022.05.31