SwiftUI - Layout 다루기

Whale·2022년 6월 14일
0

이번 목표는 보편적으로 많이 쓰는 유저 프로필 형태. 이미지 하나와 유저이름, 설명글, 추가버튼이 들어있는 간단한 레이아웃.

PeopleContentView 생성

시작을 위해 PeopleContentView 라는 뷰를 새로 만들고, ContentView에선 PeopleContentViewbody에 넣어줬다.

struct ContentView: View {
    var body: some View {
        PeopleContentView()
    }
}

struct PeopleContentView: View {
    var body: some View {
        Image("animal_01")
            .frame(width: 40, height: 40, alignment: .leading)
            .clipped()
    }
}

실행해보면 큰 화면 안에 40x40 이미지 하나만 덩그러니 있다.
그런데... 이걸 어떻게 왼쪽으로 보내야 할까? storyboard에선 오토레이아웃을 잡아서 좌측10, 세로 센터정렬을 주면 딱 들어갈텐데. 어딜 봐도 오토레이아웃에 대한 설정법이 보이지 않는다. 그래서 찾아보니...

오토레이아웃은 이제 없습니다.

아니 이게 무슨소리야. 오토레이아웃에 적응하는것도 한세월이었는데. 이젠 그게 사라졌다니?
(물론 그 전에도 잘 다룬건 아니지만.)

오토레이아웃 자체가 매우 복잡하고, 수정하나 잘못하면 모조리 다 경고가 뜨고, 싹 다 재설정도 해야하는 불편한 시스템이긴 했다. IB에서 적용해두고 코드에서 수정하는것도 매우 번거롭고. 생각해보면 사라질 이유는 충분하긴 하다.

있다면 어떻게 썼겠지만 없어진걸 어쩌겠는가. 새로운 방식에 익숙해져야지.

단순하게 이미지뷰를 좌측으로 보내기 위해 찾던 내용이 레이아웃 시스템까지 거슬러올라갔다.
결국 도달한 결론은 아래와 같다.

  1. PeopleContentView 가 자신이 표기하는 컨텐츠 크기에 맞춰서 동적으로 작성되어야 한다.
  2. PeopleContentView 는 자신의 컨텐츠보다 부모뷰가 클 경우 늘어날 위치를 지정해야한다.

요점은 기존에 동적레이아웃을 짜던 것과 같다.
자신이 늘어나거나 줄어들 위치를 명확히 해서 코드를 짜면 어디에 추가되더라도 깨지지 않는다.
이를 위해서 마치 테이블 셀을 짜던것처럼 상상하며 뷰 클래스를 디자인해야한다.

스텍뷰를 활용해야한다.

콜렉션이나 테이블 셀의 구조를 상상해보면, 셀이라는 UI파일 안에는 ContentView로 통칭되는 뷰가 있고, 우리는 그 안에 담길 컴포넌트(label, image 등등) 을 오토레이아웃으로 위치를 잡아 추가했다. 그러면 셀이 표기될때 베이스가 되는 콜렉션뷰, 테이블뷰의 크기에 따라 셀 내부의 제약조건을 보고 크기가 조정됬었다.

body 안쪽에 먼저 stackview를 깔아두고 그 안으로 이미지를 위치시켜본다.

...변한게 없는데? 이유는 단순하다. 오토레이아웃이 없으니, 스텍뷰도 자식의 크기대로 적용 후 센터로 정렬된것.

스텍뷰가 화면에 꽉 찰 수 있도록 Spacer() 를 추가하면 늘어나지 않는 이미지뷰는 좌측에 찰싹 붙고, spacer 가 동적영역이 되어 스택뷰의 나머지 영역을 차지한다.

여기까지 적성하고 나면 나머지는 쉽다. 결국 요령은 늘어날 위치에 Spacer 를 적절하게 배치하는것.
베이스가 되는 HStack 안으로 Image, VStack { Text, Text }, Spacer, Button 이 들어가도록 코드를 추가한다. 이때 Spacer의 위치가 포인트.

마무리

여기에 부모뷰와 컨텐츠 사이의 간격을 위해 HStack 뷰에 패딩값, 이미지 clip 속성을 찾아서 적용해주면 완료. 세부 속성들은 검색을 통해 충분히 얻을 수 있으니 설명하지 않는다. 결국 중요한건 레이아웃을 작업하는 방식일뿐.

이 작업에서 기억해야하는 포인트는 2개.

  1. HStack이 부모뷰에 꽉 채워지도록 제약조건을 설정할 수 없다. 그저 HStack 뷰가 늘어날 수 있도록 작성하면 꽉 채워질뿐.
  2. Spacer 는 만능이다.

struct PeopleContentView: View {
    var body: some View {
        HStack(alignment: .top, spacing: 10, content: {
            
            Image("animal_01")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 40, height: 40, alignment: .leading)
                .clipShape(Circle())
                
                
            VStack(alignment: .leading, spacing: 4, content: {
                Text("User")
                    .font(Font.headline)
                Text("Description")
                    .font(Font.subheadline)
            })
            
            Spacer()
            
            Button {
                print("more action")
            } label: {
                Image.init(systemName: "ellipsis")
            }.frame(width: 50, height: 50)
            
        })
        .padding(EdgeInsets(top: 5, leading: 20, bottom: 5, trailing: 20))
    }
}
profile
그저 오래된 iOS 개발자.

0개의 댓글