iOS/SwiftUI
[SwiftUI] Carousel Card View
HarryJeonn
2022. 8. 1. 06:21
Why ?
스와이프하면 다음 카드로 이동하는 UI를 그리고 싶어서 Horizontal ScrollView를 사용했다가 스와이프하면 자동으로 중심을 맞춰주는 뷰를 구현하고 싶었다.
How ?
GeometryReader를 활용했다.
GeometryReader { proxy in
// 스크롤하면 움직일 x축의 값
let xOffsetToShift = cardWidth + spacing
HStack(spacing: 10) {
ForEach(Array(viewModel.places.enumerated()), id: \\.0) { idx, place in
viewModel.createPlaceCard(place: place, index: idx)
}
}
.padding(.leading, 22)
// xOffsetToShift에 index를 곱해서 offset의 값을 바꿔준다.
.offset(x: offset - (CGFloat(viewModel.cardCurrentIndex) * xOffsetToShift))
.gesture(
DragGesture()
.updating($offset, body: { value, out, _ in
out = value.translation.width
})
// 어느정도 스크롤을 해야 다음 카드로 넘어갈지 계산하는 부분
.onEnded({ value in
let offsetX = value.translation.width
let progress = -offsetX / (proxy.size.width / 2)
let roundIndex = progress.rounded()
viewModel.cardCurrentIndex = max(min(viewModel.cardCurrentIndex + Int(roundIndex), viewModel.places.count - 1), 0)
viewModel.slideCard(index)
})
.onChanged({ value in
let offsetX = value.translation.width
let progress = -offsetX / (proxy.size.width / 2)
let roundIndex = progress.rounded()
index = max(min(viewModel.cardCurrentIndex + Int(roundIndex), viewModel.places.count - 1), 0)
})
)
}
.frame(height: UIScreen.main.bounds.height * 0.13)
.animation(.easeInOut, value: offset == 0)
전체 코드 중 내가 생각하는 핵심 코드부분이다.
카드의 width와 spacing을 더하여 한번 스와이프하면 움직일 x 값을 구했다.
그리고 index와 곱하여 다음 카드에 맞게 계속 움직일 수 있도록 구현했다.
🤔
처음에는 남의 코드를 가져다 쓰려고 하다보니 offset값 계산하는데 애를먹었다.
남의 코드를 보고 그냥 쓰지말고 어떻게 동작하는지 이해하고 직접 계산해보니 조금 수월했다.
역시 무지성으로 가져다가 쓰면 결국 고생하는건 나다.
이해하고 사용하자!