본문 바로가기

iOS

UIView - Content Hugging, Content Comporession Priorities

글을 작성하게 된 계기

: UIStackView의 subviews의 intrinsic Content Size만 생각하고 오토레이아웃에서 Size 지정을 안해줬다가 Content Compression Resistance Priority에 의해 사라지면 안되는 Label, Image들이 사라져서 작성하게 됨

 

요약

Intrinsic Content Size : UILabel, UIImage 등 '컨텐츠'가 있는 View의 자체 크기. 

Content Hugging Priorities : 늘어나지 않게 잡아주는 값, 낮다면 가장 먼저 크기가 늘어날 수 있다.

Compression Resistance Priorities : 줄어들지 않게 저항하는 값, 낮은 순위면 먼저 줄어든다.

 

Priority : 1 ~ 1000까지 있다.

- required = 1000, defaultHigh  = 750, defaultLow  = 250

 

 

Intrinsic Content Size 

top, leading, trailing만 제약조건을 설정한 Custom UIView

공식문서에 따르면 Custom하게 만든 UIView는 내부에 어떤 컨텐츠가 표시되는지 레이아웃 시스템이 인식하지 못한다. 그래서 사용자 정의 화면(Custom View)은 레이아웃의 위치와 크기를 계산할 수 있도록 제약조건을 설정해야 한다. top, bottom의 제약을 줘 height의 크기를 계산할 수 있게 하거나 top, bottom 둘 중 하나만 조건을 준 후 height 크기를 설정해주는 등 노력이 필요하다. 위 사진을 보면 top 제약조건만 설정해서 top 부분에 빨간선으로 경고가 떠있는걸 볼 수 있다.

 

하지만 UILabel 혹은 UIImage와 같이 필수적인 제약조건을 설정하지 않아도 레이아웃 오류가 발생하지 않는 경우가 있다.

 

Content Hugging Priority

뷰가 고유 크기보다 커지지 않도록 잡아주는 우선순위다. 

만약 Distribution의 값이 fill인 주황색 UIStackView 안에 두 개의 UILabel이 있고 둘의 Hugging Priority가 같다면 스택뷰의 순서대로 늘어나지만 위 스크린샷은 초록색 UILabel의 우선순위를 낮게 해서 초록색이 늘어났다.

보통 Content Hugging Priority의 기본값은 Horizontal, vertical 모두 251이다.

(코드로 생성하면 250)

 

 

Content Compression Resistance Priorities

뷰가 고유 크기보다 작아지지 않도록 잡아주는 우선순위다.

Compression Resistance Priorities도 같다면 스택뷰의 순서대로 작아진다. 위 스크린샷은 같은 우선순위라서 스택뷰의 순서대로 줄어들었다. 

보통 Compression Resistance Priorities의 값은 Horizontal, vertical 모두 751 이다.

(코드로 생성하면 750)

 

 

우선순위 바꾸기

스토리보드(Xib)

너무 쉽다. 뷰를 선택해주고 size inspector에서 우선순위를 정해주면 된다.

 

코드 베이스

// Content Hugging Priority
func setContentHuggingPriority(
    _ priority: UILayoutPriority,
    for axis: NSLayoutConstraint.Axis
)

// Content Comporession Resistance 
func setContentCompressionResistancePriority(
    _ priority: UILayoutPriority,
    for axis: NSLayoutConstraint.Axis
)

let SomeLabel: UILabel = {
    let label = UILabel()

    label.setContentHuggingPriority(
    	.defaultHigh,
        for: .vertical
    )
    
    label.setContentCompressionResistancePriority(
    	.required,
        for: .horizontal
    )

    return label
}()