본문 바로가기

iOS 관련 공부/SwiftUI

SwiftUI - stack views

스유를 하면서 모든 뷰는 스택에서 나오는거 같다는 생각이 들어

UI배치 공부를 위해 스택을 공부해볼까 합니다!

 

일단 공식문서를 가서 열심히 읽어봤습니다.

영어 진짜 힘드네요

자 이제 UIKit을 했다면 HStack과 VStack은 나름 이해하기 쉬울것

HStack은 horizontal, VStack은 vertical 이라고 이해하자고요?

그게 맞긴 하니까~

 

근데 ZStack은 머냐,,? 위로 쌓이는것..? 이라고 생각을 했는데

아니 이거 공식문서 예시를 보니까

대박,,

내가 만들어야 하는 뷰가...

완전 ZStack을 무조건 써야하는거 같잖아?!?!?!?!?!?

진짜 생각도 못했다;;;;;;

 

공식문서 예시 가져와도 되나,,? ㅎㅎ 일단 가져옴~

사람 사진 조금 부담스러워서 스티커 붙일게요

이 예시를 만드려면 코드가

struct ProfileView: View {
    var body: some View {
        ZStack(alignment: .bottom) {
            Image("ProfilePicture")
                .resizable()
                .aspectRatio(contentMode: .fit)
            HStack {
                VStack(alignment: .leading) {
                    Text("Rachael Chiseck")
                        .font(.headline)
                    Text("Chief Executive Officer")
                        .font(.subheadline)
                }
                Spacer()
            }
            .padding()
            .foregroundColor(.primary)
            .background(Color.primary
                            .colorInvert()
                            .opacity(0.75))
        }
    }
}

이렇게 되어야 한다네요

그니까 ZStack에 이미지랑 HStack들어가고 그 HStack에 VStack들어간다.. 오케이..

이거보고 내 뷰가 슬슬 머리속에서 정리가 조금 되어간다잉...

 

 

Stack을 써야하는 이유가 뭘까?

 

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
    }
}

이렇게 View 프로토콜을 채택한 경우

최상위 View 역할을 할 body라는 연산 프로퍼티를 필수적으로 구현해줘야 하는데

이때 body라는 프로퍼티의 타입이 some View 즉, 불투명타입(Opaque Type)이라서

내부에서 View를 준수하고있는 객체면 어떤 객체든 리턴이 가능하지만,

"단 한개의 View"만 리턴을 해야한다.

 

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
        Text("Hello, world!2")
    }
}

만약 이렇게 body 안에 두개의 Text를 위처럼 써버린다는 것은

Text라는 두 개의 View를 리턴한다는 말이 되어서 안된당..

 

따라서 만약 한 개 이상의 View를 리턴하고 싶은 경우,

SwiftUI에서는 이 View들을 하나로 감싸주면되는데

그럴 때 사용하는게 Stack, Group.. 등등이다

 

 

 

Stack을 이제 종류별로 보자고요,,

 

 

HStack

Horizontal 입니다.

서브뷰들을 수평으로 배치해주는 뷰

순서는 기본적으로 Leading에서 Trailing으로

var body: some View {
    HStack(
        alignment: .top,
        spacing: 10
    ) {
        ForEach(
            1...5,
            id: \.self
        ) {
            Text("Item \($0)")
        }
    }
}

 

 

 

VStack

Vertical 입니당.

서브뷰들을 수직으로 배치해주는 뷰

배치 방향은 기본적으로 Top 에서 Bottom

var body: some View {
    VStack(
        alignment: .leading,
        spacing: 10
    ) {
        ForEach(
            1...10,
            id: \.self
        ) {
            Text("Item \($0)")
        }
    }
}

 

 

 

ZStack

서브뷰들을 겹쳐서 두 축으로 배치

ZStack은 각 연속 서브뷰를 이전보다 높은 z축 값을 지정한다. 즉, 나중 하위 뷰가 이전의 상단에 나타난다.

let colors: [Color] =
    [.red, .orange, .yellow, .green, .blue, .purple]


var body: some View {
    ZStack {
        ForEach(0..<colors.count) {
            Rectangle()
                .fill(colors[$0])
                .frame(width: 100, height: 100)
                .offset(x: CGFloat($0) * 10.0,
                        y: CGFloat($0) * 10.0)
        }
    }
}

10으로 오프셋하여 완전히 겹치진 않는 서브뷰들 

 

다른 예제도 보자

var body: some View {
    ZStack(alignment: .bottomLeading) {
        Rectangle()
            .fill(Color.red)
            .frame(width: 100, height: 50)
        Rectangle()
            .fill(Color.blue)
            .frame(width:50, height: 100)
    }
    .border(Color.green, width: 1)
}

빨간색이 먼저 쌓이고 그 위로 파란색이 쌓이므로 저런 모습이 된당

 

 

 

정렬 방식(alignment) 변경하기

Stack들의 기본 정렬을 바꿀 때는 파라미터 값으로 alignment를 직접 설정해주면 된다

VStack(alignment: .trailing) 이런식으로..

 

 

Stack 내의 여백(spacing) 크기 변경하기

VStack의 경우 여백 값을 따로 설정하지 않으면 여백이 없어보이게 즉 spacing이 없어보이게 나와

기본 spacing의 값이 0으로 생각할 수 있지만

HStack에서 여백 설정을 안해줘도 여백이 있게 나오는 걸 볼 수 있으므로 기본 spacing값은 0이 아니다.

그래서 여백이 없게 하고싶으면 

HStack(spacing: 0)

이런식으로 설정해줘야 한다.

 

 

 

 

일단 끝

Lazy 스택들은 다음 글에서..