Carousel View In SwiftUI
In this article, We will explore how to implement a Carousal View using SwiftUI
Before proceeding, please consider subscribing to our YOUTUBE CHANNEL
It gives us a lot of motivation to produce high-quality content for you guys.
if you are interested in watching the video tutorial, Check out below.
Let's create a SwiftUI file and name it as CarouselView.
import SwiftUI
struct CarouselView: View {
var body: some View {
ZStack {
}
}
}
We need to store the values of dragged and snapped items also xDistance.
import SwiftUI
struct CarouselView: View {
var xDistance: Int = 150
@State private var snappedItem = 0.0
@State private var draggingItem = 0.0
@State var activeIndex: Int = 0
var body: some View {
ZStack {
}
}
}
We need to have child views to contain the views we need inside the carousel view.
Create a SwiftUI file and name it CarouselChildView, with View also extending it to Identifiable.
import SwiftUI
struct CarouselChildView: View, Identifiable {
var id: Int
@ViewBuilder var content : any View
var body: some View {
ZStack {
AnyView(content)
}
}
}
var placeholderCarouselChildViews: [CarouselChildView] = [
CarouselChildView(id: 1) {
ZStack {
RoundedRectangle(cornerRadius: 18)
.fill(Color.red)
Text("1")
.padding()
}
.frame(width: 200, height: 400)
},
CarouselChildView(id: 2) {
ZStack {
RoundedRectangle(cornerRadius: 18)
.fill(Color.gray)
Text("2")
.padding()
}
.frame(width: 200, height: 400)
}
,
CarouselChildView(id: 3) {
ZStack {
RoundedRectangle(cornerRadius: 18)
.fill(Color.cyan)
Text("3")
.padding()
}
.frame(width: 200, height: 400)
}
]
Loop through the views and populate.
import SwiftUI
struct CarouselView: View {
var xDistance: Int = 150
@State private var snappedItem = 0.0
@State private var draggingItem = 0.0
@State var activeIndex: Int = 0
var views : [CarouselChildView] = placeholderCarouselChildViews
var body: some View {
ZStack {
ForEach(views) { item in
item
.scaleEffect(1.0 - abs(distance(item.id)) * 0.2 )
.opacity(1.0 - abs(distance(item.id)) * 0.3 )
.offset(x: offset(item.id), y: 0)
.zIndex(1.0 - abs(distance(item.id)) * 0.1)
}
}
}
func distance(_ item: Int) -> Double {
return (draggingItem - Double(item)).remainder(dividingBy: Double(views.count))
}
func offset(_ item: Int) -> Double {
let angle = Double.pi * 2 / Double(views.count) * distance(item)
return sin(angle) * Double(xDistance)
}
}
Add a DragGesture on ZStack and set the Dragged and Snapped values inside the animation.
import SwiftUI
struct CarouselView: View {
var xDistance: Int = 150
@State private var snappedItem = 0.0
@State private var draggingItem = 0.0
@State var activeIndex: Int = 0
var views : [CarouselChildView] = placeholderCarouselChildViews
var body: some View {
ZStack {
ForEach(views) { item in
item
.scaleEffect(1.0 - abs(distance(item.id)) * 0.2 )
.opacity(1.0 - abs(distance(item.id)) * 0.3 )
.offset(x: offset(item.id), y: 0)
.zIndex(1.0 - abs(distance(item.id)) * 0.1)
}
}
.gesture(
DragGesture()
.onChanged { value in
draggingItem = snappedItem + value.translation.width / 100
}
.onEnded { value in
withAnimation {
draggingItem = snappedItem + value.predictedEndTranslation.width / 100
draggingItem = round(draggingItem).remainder(dividingBy: Double(views.count))
snappedItem = draggingItem
self.activeIndex = views.count + Int(draggingItem)
if self.activeIndex > views.count || Int(draggingItem) >= 0 {
self.activeIndex = Int(draggingItem)
}
}
}
)
}
func distance(_ item: Int) -> Double {
return (draggingItem - Double(item)).remainder(dividingBy: Double(views.count))
}
func offset(_ item: Int) -> Double {
let angle = Double.pi * 2 / Double(views.count) * distance(item)
return sin(angle) * Double(xDistance)
}
}
thats it. Below is the result.
Once again Thanks for stopping by.
Do check out our YOUTUBE CHANNEL
Social Handles
Instagram : https://www.instagram.com/mobileappsacademy/
Twitter : https://twitter.com/MobileAppsAcdmy
LinkedIn : https://www.linkedin.com/company/mobile-apps-academy/