[iOS Programming Big Nerd Ranch] 12. Stack Views


Stack View에 대해 알아보자.


지금까지는 Auto Layout을 이용해서 디바이스 타입과 크기에 따라 달라지는 유동적인 인터페이스를 만들었다. Auto Layout은 굉장히 강력한 기술이지만, 복잡성이 따른다. 인터페이스를 잘 레이어링하는 것이 종종 많은 제약이 필요할 수 있고, 따라서 제약들을 계속 추가하고 빼는 것 때문에 동적인 인터페이스를 만드는 것이 어려울 수 있다.

인터페이스는 선형으로 정렬될 수 있다. 선형 레이아웃을 가지는 인터페이스는 stack view를 이용하기 좋은 후보군에 속한다. Stack view는 일반적으로 스스로 관리해야 하는 대부분의 제약을 레이어링하고 관리하기 쉽게 수직이나 수평으로 레이아웃을 만드는 것을 가능하게 하는 UIStackView의 인스턴스다. 스택 뷰 안에 스택 뷰를 넣어서 인터페이스를 만들 수도 있다.

여기서는 특정 Item의 세부사항을 출력하는 인터페이스를 만들 것이다. 이 인터페이스에서는 수직이고 평행한 여러 개의 스택뷰가 중첩된 형태를 만들 것이다.

image

Using UIStackView

Item의 디테일을 수정하는 인터페이스를 만들 것이다. 이 글에서는 기본 인터페이스만을 구현하고, 세부사항은 다음 글에서 구현할 것이다.

먼저, 아이템의 이름, 일련 번호,, 값, 그리고 생성된 날짜를 표시하는 네 개의 요소를 담은 수직 스택 뷰를 아래와 같이 가지고 있다.

image

스토리 보드를 열고 새로운 View Controller를 캔버스에 추가한다. 그리고 이 뷰 컨트로러의 뷰로 Vertical Stack View를 오브젝트 라이브러리에서 드래그 드롭한다.

그리고 UILabel 4개를 스택 뷰에 드래그 드랍하고 텍스트를 입력한다.

여기까지 했을 때, 라벨에 빨간색으로 선이 표시되는 것을 확인할 수 있다. 이걸 해결하느 방법은 Auto Layout을 이용하거나, stack view의 프로퍼티를 사용하는 것이다. Auto Layout을 사용해서 먼저 사용해보겠다.

Implicit constraints

모든 뷰는 instrinsic content size가 있다는 것을 배웠다. 또한 만약 명시적으로 너비 높이를 지정하지 않았다면 뷰가 instrinsic content size에서 너비와 높이를 불러올 것이라고 했다.

이게 작동하는 과정은 뷰의 content hugging 프로퍼티와 content compression resistance 프로퍼티에서 정해진 implicit constraint를 이용하기 때문이다. 뷰는 이 프로퍼티를 각각의 축에 대해 갖고 있다.

  • horizontal content hugging priority
  • vertical content hugging priority
  • horizontal content compression resistance priority
  • vertical content compression resistance priority

Content hugging priority

Content hugging priority는 뷰에 둘러싸여진 고무 밴드같다. 고무 밴드는 뷰가 해당 차원에서 intrinsic content size보다 커지지 않게 한다. 각 우선순위는 0에서 1000까지의 값을 갖고 있다. 1000은 뷰가 해당 차원에서 intrinsic content size보다 절대로 커질 수 없다는 의미다.

horizontal dimension을 예시로 들겠다. 두개의 라벨이 아래와 같이 붙어있다고 해보자.

image

이는 superview가 커지기 전까지는 잘 동작한다. 만약 어떤 라벨이 더 커져야 한다면 첫 번째게 커질까 아니면 두 번째, 혹은 둘 다 커질까?

image

여기서 hugging priority가 관여한다. 더 높은 content hugging 우선순위를 가진 애가 확장되지 않는다. 이 우선순위의 값을 고무 밴드의 탄력성, 강도라고 생각하면 된다. 더 높은 값을 가질 수록 고무 밴드가 더 세지는 것이다.

Content compression resistance priorities

Content compression resistance 우선순위는 뷰가 intrinsic content size보다 작아지는 것을 얼마나 저항할지를 결정한다. 위의 예시에서 superview의 너비가 줄어들었다면 어떤 라벨의 글자가 잘릴까?

image

더 높은 content compression resistance 우선순위를 가진 뷰가 축소되는 것을 더 강하게 저항할 것이기 때문에 축소되지 않는다.

지금까지 본 내용을 바탕으로 앞에서의 스택 뷰 문제를 해결할 수 있다.

맨 아래의 라벨을 선택해서 inspector에서 vertical content huggin priority를 249로 낮추면, 위의 세 개의 라벨을 더 높은 content hugging 우선순위를 갖기 때문에 모두 내부의 content 높이대로 정해진다. 맨 아래 라벨은 남은 공간을 꽉 채울 것이다.

image

Stack view distribution

이걸 해결하는 다른 방법으 ㄹ보겠다. 스택 뷰는 content가 어떻게 레이아웃 되는지 정하는 여러 프로퍼티들이 있다.

스택 뷰를 선택해서 inspector에서 distribution 프로퍼티를 찾는다. 현재는 Fill로 채워져 있는데, 이거는 뷰들을 그들의 instrinsic content size에 기반한해 뷰의 컨텐츠를 레이어링 하겠다는 것이다. 이를 Fill Equaly로 변경하면 내부의 라벨들이 intrinsic content size를 무시하고 모두 같은 높이를 갖게 된다. 다시 Fill로 바꿔서 진행해보도록 하겠다.

Nested stack views

스택 뷰의 가장 강력한 특징 중 하나는 중첩이 가능하다는 것이다. 수직 스택 뷰 안에다가 수평 스택 뷰를 넣어볼 것이다. 위 세 개의 라벨은 Item과 일치하는 값을 나타내는 텍스트 필드를 가질 것이고 사용자가 이 값을 수정할 수 있게 할 것이다.

맨 위 라벨을 선택한 후 Auto Layout 을 설정하는 탭의 맨 오른쪽 아이콘을 클릭해서 Stack View를 선택한다. 그리고 axis를 horizontal로 바꿔준다. 그리고 Text Field를 드래그 해서 드롭한다. 라벨은 기본적으로 텍스트 필드보다 더 높은 hugging priority를 갖고 있기 때문에 라벨은 내부의 intrinsic content width에 맞춰지고 text Field가 확장된다. 라벨과 텍스트 필드는 현재 같은 content compression resistance priority를 갖고 있기 때문에 텍스트 필드의 텍스트가 너무 길어질 경우 레이아웃이 모호해 질 수 있다. 따라서 텍스트 필드의 horizontal content compression resistance priority를 749로 조정해준다. 이거는 텍스트 필드의 텍스트가 잘리게 하고 라벨의 텍스트는 줄어들지 않게 한다.

Stack view spacing

라벨과 텍스트 필드는 그 사이에 여백이 없어서 너무 뭉쳐져 보인다. 스택 뷰는 아이템 사이의 여백을 조절할 수 있게 해준다. horizontal stack view를 선택해서 Spacing을 8로 조정한다. 이러면 텍스트 필드가 저항성이 현재 더 낮게 설정되어 있기 때문에 텍스트 필드가 여백만큼 줄어든다.

이를 밑의 라벨들에도 반복한다.

이 외에도 추가적으로 해야 할 일이 있다. 수직 스택 뷰도 여백이 사이사이에 필요하고, 맨 밑의 라벨은 텍스트가 가운데 정렬이 되어야 한다. 또한 위의 세 개의 라벨은 모두 같은 너비를 가지고 있어야 한다.

먼저 수직 스택뷰의 Spacing을 8로 조정한다. 그리고 맨 밑의 라벨의 Alignment를 중앙 정렬로 바꾼다.

스택뷰가 내가 인터페이스에 추가해야 하는 제약의 수를 줄여준다고 해도, 어떤 제약은 여전히 중요하다. 텍스트 필드는 라벨의 너비가 제각각이어서 동일한 위치에서 시작되지 않는다. 영어에서의 차이는 미미하지만, 다른 언어로 바뀌었을 때 차이가 부각될 수 있다. 이를 해겨하기 위해 세 개의 텍스트 필드에 leading edge 제약을 추가한다.

스택 뷰는 또한 실행 도중에 변동성 있는 인터페이스를 가질 수 있게 한다. addArrangedSubview, insertArrangedSubview, removeArrangedSubview를 이용해서 스택 뷰에서 뷰를 더하고 뺄 수 있다. 또한 스택 뷰의 뷰의 hidden 프로퍼티를 토글할 수도 있다. 스택 뷰는 이 값에 맞추기 위해 컨텐츠를 자동으로 레잉어링한다.

Segues

대부분의 iOS 앱들은 사용자가 전환할 수 있는 여러 개의 뷰 컨트롤러를 가지고 있다. 스토리보드는 코드를 작성하는 것 대신에 segues를 이용해서 이 상호작용을 설정할 수 있게 한다.

Segue는 다른 뷰 컨트롤러의 뷰를 화면에 띄우며 UIStoryboardSegue의 인스턴스에 의해 나타나진다. 각 segue는 style, action item, 그리고 identifier가 있다. segue의 style은 어떻게 뷰 컨트롤러가 나타날지를 결정한다. Action item은 버튼, 테이블 뷰 cell, 그리고 다른 UIControl과같이 segue를 발생시키는 스토리보드에 있는 뷰 객체다. Identifier는 segue를 코드 상에서 접근하는데 사용된다. 이거는 shake나 스토리 보드 파일에서 세팅 될 수 없는 다른 인터페이스 요소와 같이, action item에서 발생할 수 없는 segue를 실행시키고 싶을 때 유용하다.

Show segue를 보자. Show segue는 보여지는 컨텍스트에 따라 뷰 컨트롤러를 보여준다. segue는 테이블 뷰 컨트롤러와 새로운 뷰 컨트롤러 사이에 있을 것이다. action item은 테이블 뷰의 cell이 될 것이고, 각 cell을 터치하는 것이 뷰 컨트롤러를 보여줄 것이다.