Where who wants to meet someone

[1주차] 3. stackView의 장점과 단점에 대해서 설명하시오 본문

Apple Developer/면접 스터디

[1주차] 3. stackView의 장점과 단점에 대해서 설명하시오

Lust3r 2023. 7. 4. 14:40
728x90

  1. Optional이란 무엇인지 설명하시오.
  2. KVO 동작 방식에 대해 설명하시오.
  3. stackView의 장점과 단점에 대해서 설명하시오.

UIStackView | Apple Developer Documentation

 

UIStackView | Apple Developer Documentation

A streamlined interface for laying out a collection of views in either a column or a row.

developer.apple.com

column이나 row에 view의 모음을 배치하기 위한 간소화된 인터페이스

 

Overview

stackView를 사용하면 Auto Layout의 기능을 활용하여 장치의 방향, 화면 크기 및 사용 가능한 공간의 변경 사항에 동적으로 적응할 수 있는 사용자 인터페이스를 생성할 수 있다.

stackViewarrangedSubviews 속성에서 모든 뷰의 레이아웃을 관리한다.

 

What is arrangedSubviews?

arrangedSubviews | Apple Developer Documentation

 

arrangedSubviews | Apple Developer Documentation

The list of views arranged by the stack view.

developer.apple.com

stackViewarrangedSubviews 배열이 항상 하위 뷰 배열의 하위 집합임을 확인. 따라서 addArrangedSubview(_:) 메서드가 호출될 때마다 stackView는 해당 viewsubview추가한다(해당 view가 아직 없는 경우). arranged view의 removeFromSuperview() 메서드가 호출될 때마다 stackViewarrangedSubviews 배열에서 view를 제거

 

arranged subviews를 관리하는 방법으로는 다음 세 메서드가 있다.

  1. addArrangedSubview(UIView): arranged subviews 배열의 마지막에 view를 추가
  2. insertArrangedSubview(UIView, at: Int): arranged subviews 배열의 특정한 인덱스에 제공된 view를 추가
  3. removeArrangedSubview(UIView): arranged subviews에서 view를 제거

다시 돌아와서, 이러한 view는 arranged된 배열의 순서에 따라 axis에 맞게 정렬된다.

정확한 레이아웃은 stackView의 axis, distribution, alignment, spacing과 다른 속성에 따라 달라진다.


What is axis?

axis | Apple Developer Documentation

 

axis | Apple Developer Documentation

The axis along which the arranged views lay out.

developer.apple.com

- vertical(세로), horizontal(가로) 값을 갖고 있음


What is distribution?

distribution | Apple Developer Documentation

 

distribution | Apple Developer Documentation

The distribution of the arranged views along the stack view’s axis.

developer.apple.com

- 다음의 5가지 케이스 값을 가지며 기본값은 fill

1. fill: 정렬된 view가 stackView에 맞지 않으면 compression resistance priority에 따라 view를 축소. 정렬된 view가 stackView를 채우지 않으면 hugging priority에 따라 view를 확장함. 만약 모호성이 있는 경우 stackView는 arrangedSubviews 배열의 인덱스를 기반으로 크기를 조정

2. fillEqually: view는 stackView의 축을 따라 모두 같은 크기가 되도록 크기를 조정.

3. fillProportionally: view는 stackView의 축을 따라 고유 콘텐츠 크기에 따라 비례적으로 크기가 조정됨.

4. equalSpacing: arranged view가 stackView를 채우지 않으면 view 사이의 간격을 고르게 채움. arranged view가 stackView에 맞지 않으면 compression resistance priority에 따라 view를 축소.

모호성이 있는 경우 stackView는 arrangedSubviews 배열의 인덱스를 기준으로 view를 축소

5. equalCentering: arranged view가 stackView에 맞지 않으면 spacing 속성에 정의된 최소 간격에 도달할 때까지 간격을 줄임.

view가 여전히 맞지 않으면 stackView는 compresstion resistance priority에 따라 arranged view를 축소.

모호성이 있는 경우 stackView는 arrangedSubviews 배열의 인덱스를 기준으로 view를 축소


What is alignment?

alignment | Apple Developer Documentation

 

alignment | Apple Developer Documentation

The alignment of the arranged subviews perpendicular to the stack view’s axis.

developer.apple.com

- 다음의 6가지 case, 2가지 전역 변수를 가짐

1. fill: stackView의 축에 수직으로 사용 가능한 공간을 채우도록 arranged views의 크기를 조정하는 레이아웃

2. center: stackView가 arranged views의 중심을 축을 따라 중심에 맞추는 레이아웃

3. leading: stackView가 arranged views의 leading을 stackView의 leading edge에 따라 정렬하는 vertical 스택용 레이아웃

4. trailing: stackView가 arranged views의 trailing을 stackView의 trailing edge에 따라 정렬하는 vertical 스택용 레이아웃

5. firstBaseline: stackView가 first baseline을 기준으로 arranged views를 정렬하는 horizontal 스택용 레이아웃

6. lastBaseline: stackView가 last baseline을 기준으로 arranged views를 정렬하는 horizontal 스택용 레이아웃

7. (Type Property) top: stackView가 arranged views의 top을 stackView의 top edge에 따라 정렬하는 horizontal 스택용 레이아웃

8. (Type Property) bottom: stackView가 arranged views의 bottom을 stackView의 bottom edge에 따라 정렬하는 horizontal 스택용 레이아웃


What is spacing?

spacing | Apple Developer Documentation

 

spacing | Apple Developer Documentation

The distance in points between the adjacent edges of the stack view’s arranged views.

developer.apple.com

- distribution의 fillProportionally 속성에 대해 arranged views 사이의 엄격한 간격을 정의하는 속성

- 또한 distribution의 equalSpacing, equalCentering 속성에 대해 최소 간격을 나타냄.

- 겹침을 허용하려면 음수 값을 사용하면 되고, 기본값은 0.0


Stack view and Auto Layout

stackViewAuto Layout을 사용하여 arranged views를 배치하고 크기를 조정함.

stackView첫 번째마지막으로 arrange된 view를 stackView의 axis를 따라 edge와 정렬함. horizontal stackView에서 이것은 첫 번째 arrange된 view의 leading edge가 stackView의 leading edge에 고정되고, 마지막 arrange된 view의 trailing edge가 stackView의 trailing edge에 고정됨을 의미.

vertical stackView에서 topbottom edge는 각각 stackView의 top, bottom edge에 고정됨.

stackViewisLayoutMarginsRelativeArrangement 속성을 true로 설정하면 stackView는 콘텐츠를 edge대신 relevant 여백에 고정한다.

 

distributionfillEqually를 제외한 모든 속성의 경우 stackView는 axis를 따라 크기를 계산할 때 각 arrange된 view의 intrinsicContentSize 속성을 사용한다.

fillEqually는 arrange된 모든 view의 크기를 동일하게 조정하여 해당 axis를 따라 stackView를 채움. 가능한 경우 stackView는 axis를 따라 가장 긴 intrinsic size의 view와 일치하도록 모든 arrange된 view를 확장함.

 

alignmentfill 정렬을 제외한 모든 정렬의 경우 stackView는 stack axis에 수직으로 크기를 계산할 때 각 arrange된 view의 intrinsicContentSize 속성을 사용. fill은 arrange된 모든 view의 크기를 조정하여 해당 axis에 수직으로 stackView를 채움.
가능한 경우 stackView는 stack의 axis에 수직으로 가장 큰 intrinsic size의 view와 일치하도록 모든 arrange된 view를 확장함.

 

Position and size the stack view

stackView를 사용하면 Auto Layout직접 사용하지 않고도 내용을 배치할 수 있지만 stackView 자체의 위치를 지정하려면 여전히 Auto Layout을 사용해야 함. 일반적으로 이는 위치를 정의하기 위해 stackView의 인접한 가장자리(edge)를 두 개 이상 고정하는 것을 의미한다. (가령 leading, trailing / top, bottom) 추가 제약 없이 시스템은 콘텐츠를 기반으로 stackView의 크기를 계산한다.

  • stackViewaxis를 따라 stackViewfitting size는 arrange된 모든 view 크기의 합view 사이의 공간을 더한 것과 같음
  • stackViewaxis에 수직으로 fitting size가장 큰 arrange된 view의 크기와 같음
  • stackViewisLayoutMarginsRelativeArrangement 속성이 true로 설정되면 stackViewfitting sizemargin을 포함하도록 증가함.

stackView의 높이, 너비 또는 둘 다를 지정하는 추가 제약 조건을 제공할 수 있음.

이러한 경우 stackView는 지정된 영역을 채우기 위해 arranged views의 레이아웃과 크기를 조정함. 정확한 레이아웃은 stackView의 속성에 따라 다름.

stackView가 콘텐츠에 대한 추가 공간 또는 공간 부족을 처리하는 방법에 대한 전체 설명은 distribution이나 alignment를 참조
(상단의 각 속성에 대한 설명을 보거나, 바로 윗 Stack view and Auto Layout 단락의 마지막 두 문단을 봐도 됨)

 

top, bottom 또는 center Y를 사용하는 대신 first baseline, last baseline을 기준으로 stackView를 배치할 수도 있음.

stackViewfitting size와 마찬가지로 이러한 baseline(기준선)은 stackView의 콘텐츠를 기반으로 계산된다.

  • horizontal stackView는 forFirstBaselineLayoutforLastBaselineLayout 메서드 모두에 대해 가장 큰 view를 반환한다. 만약 가장 큰 view가 또한 stackView라면(stackView 안에 일반 view들만 있는 것이 아니라 view + stackView나 stackView + stackView 같은 구성) 그 중첩된 stackView에서 똑같은 메서드를 호출한 결과를 반환한다.
  • vertical stackView는 forFirstBaselineLayout에 대해 첫 번째 arrange된 view를, forLastBaselineLayout에 대해 마지막에 arrange된 view를 반환한다. 이러한 view중 하나가 stackView인 경우 이 역시 중첩 stackView에서 동일한 메서드를 호출한 결과를 반환한다.
Baseline 정렬은 높이가 intrinsic content size의 높이와 일치하는 view에서만 작동한다.
view가 늘어나거나 압축되면 baseline이 잘못된 위치에 나타난다.

 

Define common stack view layouts

stackView를 사용하여 콘텐츠를 배치하는 일반 방식

- Define the position only(위치만 정의)

인접한 가장자리 중 두 개를 superView에 고정하여 stackView의 위치를 정의할 수 있음.

이 경우 stackView의 크기는 arranged views를 기반으로 두 차원에서 자유롭게 커진다. 이 접근 방식은 stackView의 콘텐츠를 intrinsic content size로 표시하고 stackView와 관련하여 다른 사용자 인터페이스 요소를 정렬하려는 경우에 특히 유용하다.

 

다음 이미지는 leadingtop 가장자리가 superView에 고정된 stackView를 보여준다. 레이블은 first baseline으로 정렬되며 그 사이에 8pt 간격으로 stackView의 내용을 superView에서 왼쪽 정렬한다.

- Define the stack's size along its axis(stack의 축을 따라 크기 정의)

이 경우 해당 axis를 따라 stack의 양쪽 가장자리를 superView에 고정하여 해당 차원에서 stackView의 크기를 정의한다.

또한 다른 가장자리 중 하나를 고정하여 stackView의 위치를 정의해야 한다. stackView는 정의된 공간을 채우기 위해 축을 따라 콘텐츠의 크기를 조정하고 배치한다. 그러나 고정되지 않은 가장자리는 arrange된 가장 큰 view의 크기에 따라 자유롭게 움직인다.

 

다음 이미지는 superView에 고정된 leading, top, trailing이 있는 stackView를 보여준다. distribution.fill을 사용하면 내용이 view의 너비를 채우도록 크기가 조정되고, textField는 레이블보다 content-hugging 우선순위가 낮기 때문에 필요에 따라 늘어난다.

- Define the stack's size perpendicular to its axis(축에 수직인 stack의 크기 정의)

이 접근 방식은 위의 axis에 따라 크기를 정의한 방식과 유사하지만 stackViewaxis에 수직인 두 가장자리를 고정하고 axis를 따라 하나의 가장자리만 고정한다. 이렇게 하면 arranged views를 추가하고 제거할 때 stackView가 해당 axis를 따라 확장 및 축소된다.

UIStackView.Distribution.fillEqually distribution을 사용하지 않는 한 arranged views의 크기는 intrinsic content size에 따라 조정된다. axis에 수직으로 stackView의 정렬을 기반으로 정의된 공간에 view가 배치된다.

 

다음 이미지는 4개의 레이블과 버튼이 포함된 수직 stack을 보여준다. 8pt 간격과 중앙 정렬을 사용하고, 항목이 스택에 추가되거나 스택에서 제거됨에 따라 stackView의 높이가 늘어나고 줄어든다.

(맨 처음에 말했던, axis에 수직인 두 가장자리, axis에 따른 하나의 가장자리는 아래 이미지에 대입하면 다음과 같다.

vertical stackView이기 때문에 수직인 두 가장자리는 leading, trailing이고, 축에 따른 하나의 가장자리는 top이 된다.

그렇기 때문에 스택에 항목이 추가되면 고정하지 않은 bottom 방향으로 스택의 높이가 늘어나고, 제거하면 위로 줄어드는 것)

- Define the size and position of the stack view(stackView의 크기와 위치를 정의)

이 경우 stackView의 네 모서리를 모두 고정하여 stackView가 제공된 공간 내에 콘텐츠를 배치하도록 함.

 

다음 이미지는 4개의 가장자리가 모두 superView에 고정된 vertical stackView를 보여준다. 중앙 정렬 및 fill distribution을 사용하여 stackView는 컨텐츠가 수평 중앙에 배치되고 수직으로 화면을 채운다.

그러나 이러한 접근 방식으로 원하는 레이아웃을 얻으려면 몇 가지 추가 단계가 필요하다,

기본적으로 stackView는 imageView가 아닌 레이블을 세로로 늘린다. imageView의 크기를 조정하려면 content-hugging 우선순위를 레이블의 content-hugging 우선순위보다 낮춰야 한다.

또한 크기가 조정될 때 imageView의 종횡비를 유지하려면 해당 모드를 Aspect Fit으로 설정해야 한다.

imageView와 stackView 사이에 동일한 너비 제약 조건을 추가하면 사용 가능한 공간을 채울 수 있도록 이미지 크기를 조정할 수 있다.

 

Manage the stack view's appearance

stackView는 arranged views의 위치와 크기를 관리한다. stackView가 콘텐츠를 배치하는 방법을 정의하는 여러 속성이 있다.

  • axis: stack의 방향(세로-vertical, 가로-horizontal)을 결정
  • distribution: stack의 축에 따라 arranged views의 레이아웃을 결정(날 따라왔으니 분배해주지!)
  • alignment: stack의 축에 수직으로 arranged views의 레이아웃을 결정(나랑 다른 방향이니까 정렬해!)
  • spacing: arranged views간의 최소한의 공간을 결정
  • isBaselineRelativeArrangement: view 사이의 세로 간격이 baseline에서 측정되는지 여부를 결정
  • isLayoutMarginsRelativeArrangement: stackView가 layout margins에 연관되게 arranged views를 배치할지 여부를 결정

일반적으로 단일 stackView를 사용하여 적은 수의 항목을 배치한다. 다른 stackView 내에 stackView를 중첩하여 더 복잡한 view 계층 구조를 구축할 수 있음. 예를 들어 다음 이미지는 두 개의 horizontal stackView를 포함하는 vertical stackView를 보여준다.

각 horizontal stackView에는 label과 textField가 포함되어 있다.

arranged view에 추가 제약 조건을 추가하여 arranged view의 모양을 미세 조정할 수도 있다. 예를 들어 제약 조건을 사용하여 view의 최소 또는 최대 높이 또는 너비를 설정할 수 있다. 또는 view의 종횡비를 정의할 수 있다.

stackView는 콘텐츠를 배치할 때 이런 제약 조건을 사용한다.

 

stackView 내부에 제약 조건을 추가할 때 충돌이 발생하지 않도록 주의해야 한다.
일반적으로 view의 크기가 지정된 차원에 대한 기본 콘텐츠 크기로 다시 기본 설정되면 해당 차원에 대한 제약 조건을 안전하게 추가할 수 있다.

 

Maintain consistency between the arranged views and subviews

stackView는 arrangedSubviews 속성이 항상 subviews 속성의 하위 집합임을 확인한다. 특히 stackView는 다음 규칙을 적용

  • stackViewarrangedSubviews 배열에 view를 추가할 때 해당 view도 하위 view로 추가한다(아직 추가되지 않았다면)
  • stackView에서 하위 view가 제거되면 stackViewarrangedSubviews 배열에서도 하위 view를 제거
  • arrangedSubviews 배열에서 view를 제거해도 하위 view로 제거되지 않음. stackView는 더 이상 view의 크기와 위치를 관리하지 않지만 view는 여전히 view 계층 구조의 일부이며 표시되는 경우 화면에 렌더링된다.

arrangedSubviews 배열에는 항상 subviews 배열의 하위 집합이 포함되지만 이러한 배열의 순서는 독립적으로 유지된다.

  • arrangedSubviews 배열의 순서는 stack에 view가 표시되는 순서를 정의.
    horizontal stack의 경우 view는 읽기 순서로 배치되며 낮은 인덱스 view가 상위 인덱스 view 앞에 나타난다.
    예를 들어 영어권에서는 view가 왼쪽에서 오른쪽으로 순서대로 배치된다.
    vertical stack의 경우 view는 위에서 아래로 배치되며 낮은 인덱스 view가 상위 인덱스 view 위에 배치된다.
  • subviews 배열의 순서는 하위 view의 z순서를 정의. view가 겹치면 인덱스가 낮은 하위 view가 인덱스가 높은 하위 view 뒤에 나타남.

 

Change the stack view's content dynamically

stackView는 view가 arrangedSubviews에 추가, 제거 또는 삽입될 때마다 또는 arrangedSubviews중 하나의 isHidden 속성이 변경될 때 레이아웃을 자동으로 업데이트한다.

// Appears to remove the first arranged view from the stack.
// The view is still inside the stack, it's just no longer visible, and no longer contributes to the layout.
let firstView = stackView.arrangedSubviews[0]
firstView.isHidden = true

stackView는 또한 그것의 속성 변화에 자동적으로 대응한다. 가령 stackView의 axis 속성을 업데이트함으로써 stack의 방향을 동적으로 변경할 수 있다.

// Toggle between a vertical and horizontal stack.
if stackView.axis == .horizontal {
    stackView.axis = .vertical
}
else {
    stackView.axis = .horizontal
}

또한 앞서 봤던 arranged subview의 isHidden 프로퍼티와 stackView의 프로퍼티 변경은 animation block 안에 둠으로써 그 변화를 애니메이션화 할 수 있다.

// Animates removing the first item in the stack.
UIView.animate(withDuration: 0.25) { () -> Void in
    let firstView = stackView.arrangedSubviews[0]
    firstView.isHidden = true
}

마지막으로, Interface Builder에서 직접 많은 stackView 속성에 대한 size-class별 값을 정의할 수 있다.

시스템은 stackView의 size-class가 변경될 때마다 이러한 변경 사항을 자동으로 애니메이션화 한다.