궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
SWIFTUI/View layout

SwiftUI : ScrollView

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

ScrollView

SwiftUIScrollView를 사용하면 뷰의 Scroll 컨테이너를 비교적 쉽게 만들 수 있습니다. 그 이유는 내부에 배치 한 콘텐츠에 맞게 자동으로 크기가 조정되고 안전 영역을 피하기 위해 추가 삽입물을 자동으로 추가하기 때문입니다.

 

List / form으로 Scroll되는 데이터 테이블을 만드는 방법도 있지만, 임의 날짜를 Scroll하려는 경우에는 ScrollView로 전환해야 합니다. 예시로 1부터 100까지 나오는 ScrollView를 만들어 봅시다.

ScrollView() {
            VStack {
                ForEach(1..<100) {
                    Text("Item \($0)") //$표시 필수
                        .font(.title)
                }
            } //VStack
        }

frame(maxWidth: .infinity)

위 코드처럼 작성하면 1 부터 100까지 나와있는 것을 확인할 수 있지만, 화면 중앙을 탭 해야 Scroll이 작동됩니다.

이것은 효율성이 떨어지기 때문에 아래 코드를 추가해주면 해결이 가능합니다.

//ScrollView 내부에서 사용
.frame(maxWidth: .infinity)
ScrollView() {
            VStack {
                ForEach(1..<100) {
                    Text("Item \($0)") //$표시 필수
                        .font(.title)
                }
            } //VStack
            
            //중앙에서만 탭(스크롤)이 가능했던것을 프레임으로 전체로 늘려줌
            .frame(maxWidth: .infinity)  
        }

Horizontal 방향으로 변경

ScrollView는 기본적으로 수직이지만, 첫 번째 매개 변수로 .horizontal을 전달하여 축을 제어할 수 있습니다. 따라서 이전 예제를 다음과 같이 수평으로 뒤집을 수 있습니다.

        ScrollView(.horizontal) {
            HStack {
                ForEach(0..<10) {
                    Text("숫자 \($0)")
                        .foregroundColor(.black)
                        .font(.largeTitle)
                        .background(Color.yellow)
                }
            }
            .frame(maxHeight: .infinity)
        }

struct ContentView: View {
    var body: some View {
        VStack {
            Divider()
            ScrollView(.horizontal) {
                HStack {
                    ForEach(0..<100) { i in
                        CircleView(label: "\(i)")
                            .foregroundColor(.white)
                    }
                }
                .padding()
            }
            .frame(height: 100)
            Divider()
            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
struct CircleView: View {
    @State var label: String
    var body: some View {
        ZStack {
            Circle()
                .fill(Color.blue)
                .frame(width: 70, height: 70)
            Text(label)
        }
    }
}

스크롤 바 숨기기

ScrollView코드를 작성 후 괄호()를 열어보면 아래와 같이 스니팻 목록이 나오게 됩니다.

이 코드를 사용하여 스크롤바를 숨기거나 타나 나게 할 수 있고, 또 위에서 배웠던 방향을 쉽게 정해줄 수 있습니다.

 

우선 기본적인 ScrollView코드와 indicators을 사용한 코드를 비교해 볼게요.

ScrollView {
    VStack {
        ForEach(0..<50) { index in
            Circle()
                .fill(Color.red)
                .frame(height: 100)
            
        }
    }
}
ScrollView(.vertical, showsIndicators: false, content:  {
    VStack {
        ForEach(0..<50) { index in
            Circle()
                .fill(Color.red)
                .frame(height: 100)
            
        }
    }
})

이제 방향을 정해줄 수 있는데 vertical으로 정해주면 VStack을 자식 뷰로 채택해야 하고, horizontal이면 HStack을 채택해야 합니다.

Vertical

ScrollView(.vertical, showsIndicators: false, content:  {
    VStack {
        ForEach(0..<50) { index in
            Circle()
                .fill(Color.red)
                .frame(height: 100)
                .overlay(Text("vertical").foregroundColor(.white))
        }
    }
})

Horizontal

ScrollView(.horizontal, showsIndicators: false, content:  {
    HStack {
        ForEach(0..<50) { index in
            Circle()
                .fill(Color.red)
                .frame(width: 100)
                .overlay(Text("horizontal").foregroundColor(.white))
        }
    }
})

ScrollView 안에 ScrollView

기본적으로 ScrollViewVertical로 되어 있습니다. 그런데 기본적으로 세로 방향은 유지하되, 각 행에는 Horizontal 형식의 아이템이 오게 할 수도 있습니다. 바로 ScrollView안에 자식 뷰로 ScrollView를 넣어주는 것이죠. 코드로 살펴보겠습니다.

ScrollView {
    VStack {
        ForEach(0..<20) { index in
            ScrollView(.horizontal, showsIndicators: false, content: {
                HStack {
                    RoundedRectangle(cornerRadius: 20)
                        .fill(Color.white)
                        .frame(width: 200, height: 150)
                        .shadow(radius: 10)
                        .padding()
                }
            })
        }
    }
}

이렇게 코드를 작성하고 프리뷰를 실행해볼게요.

그럼 위 아이템에 horizontal아이템을 어떻게 넣을까요? 바로 ForEach문을 다시 한번 넣어줘야 합니다.

ScrollView {
    VStack {
        ForEach(0..<20) { index in
            ScrollView(.horizontal, showsIndicators: false, content: {
                HStack {
                    ForEach(0..<10)  { _ in
                        RoundedRectangle(cornerRadius: 20)
                            .fill(Color.white)
                            .frame(width: 200, height: 150)
                            .shadow(radius: 10)
                            .padding()
                    }
                }
            })
        }
    }
}

LazyV(H)Stack

위에서 ForEach로 아이템을 20개가 생기도록 만들어줬습니다.

 

하지만 이 아이템이 100개 혹은 300개 이상이라고 할 때 한 가지 문제가 있습니다. 만약 사용자가 앱을 클릭해서 로드를 한다면 한 번에 100개의 아이템이 로드되고 만약 이미지가 많거나 고화질일수록 로드하는데 시간이 많이 걸리죠.

 

이럴 때 사용해야 하는 것이 LazyStack입니다.

 

Lazy는 스크롤을 할 때 그 화면에 보이는 아이템이 동시에 다운로드됩니다. 그렇기 때문에 광대한 데이터 사용을 막아 줄 수 있죠.

 

사용법은 아주 간단합니다.

 

그저 VStackHStackLazyVStack / LazyHStack으로 수정해주기만 하면 됩니다.

ScrollView {
    LazyVStack {
        ForEach(0..<20) { index in
            ScrollView(.horizontal, showsIndicators: false, content: {
                LazyHStack {
                    ForEach(0..<10)  { _ in
                        RoundedRectangle(cornerRadius: 20)
                            .fill(Color.white)
                            .frame(width: 200, height: 150)
                            .shadow(radius: 10)
                            .padding()
                    }
                }
            })
        }
    }
}

 

 

읽어주셔서 감사합니다🤟

 

이 글도 읽어보세요

SwiftUI : Lazy V(H)Stack

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.