0

I am trying to make an automatic custom paged scroll view but I have run into an issue. I specified in my code for every 5 seconds to add an increment of 1 and go to the next page and organized text to each card with Identifiable. This is not happening in the preview. Instead, it is refusing to move and it is wanting to move only to the first card. When I put a fixed string value and remove the array that I have made, it works. I have tried to use other alternatives like an enum and a fixed array embedded in the view but none of that worked. Please review my code below…

struct TestView: View {
private var amount = 1
private let timer = Timer.publish(every: 5, on: .main, in: .common).autoconnect()
@State private var currentIndex = 0
var item: Item = items[0]
var body: some View {
    ZStack {
        ScrollViewReader { scrollProxy in
            SnappingScrollView(.horizontal, decelerationRate: .fast, showsIndicators: false) {
                ForEach(items) { item in
                    ForEach(0..<amount) { selection in
                        GeometryReader { geometry in
                            ZStack {
                                Rectangle()
                                    .foregroundColor(Color.black.opacity(0.2))
                                    .blur(radius: 7)
                                    .frame(maxWidth: 350, maxHeight: 300, alignment: .center)
                                    .cornerRadius(16)
                                    .shadow(color: Color.black.opacity(0.2), radius: 20, x: 0, y: 0)
                                    .offset(x: 15, y: 50)
                                    .rotation3DEffect(Angle(degrees: (Double(geometry.frame(in: .global).minX) - 30) / -20), axis: (x: 0, y: 1.0, z: 0))
                                Rectangle()
                                    .stroke(lineWidth: 50)
                                    .foregroundColor(.gray)
                                    .blur(radius: 100)
                                    .frame(maxWidth: 350, maxHeight: 300, alignment: .center)
                                    .cornerRadius(16)
                                    .shadow(color: Color.black.opacity(0.3), radius: 1)
                                    .offset(x: 15, y: 50)
                                    .rotation3DEffect(Angle(degrees: (Double(geometry.frame(in: .global).minX) - 30) / -20), axis: (x: 0, y: 1.0, z: 0))
                                VStack {
                                    Text(item.title)
                                        .font(.title2)
                                        .fontWeight(.bold)
                                        .padding(.bottom, 10)
                                    Text(item.description)
                                        .font(.system(size: 16))
                                    Image(item.image)
                                        .resizable()
                                        .frame(width: 90, height: 90)
                                        .cornerRadius(25)
                                        .padding(.bottom, -30)
                                        .padding(.top)
                                    Text("\(selection)")
                                        .opacity(0)
                                }
                                .frame(width: 300)
                                .multilineTextAlignment(.center)
                                .offset(y: 20)
                                .rotation3DEffect(Angle(degrees: (Double(geometry.frame(in: .global).minX) - 30) / -20), axis: (x: 0, y: 1.0, z: 0))
                                .padding(.leading, 25)
                                .padding(.top, 70)
                            }
                        }
                        .frame(width: 400, height: 500)
                        .offset(x: 12)
                        .id(selection)
                        .scrollSnappingAnchor(.bounds)
                    }
                }
            }
            .onReceive(timer) { _ in
                currentIndex = currentIndex < amount-1 ? currentIndex + 1 : 0
                withAnimation {
                    scrollProxy.scrollTo(currentIndex) // scroll to next .id
                }
            }
        }
    }
}

}

The Identifiable array

struct Item: Identifiable {
var id = UUID()
var title: String
var description: String
var image: String

}

var items = [
    Item(title: "Welcome to Mathematically!", description: "It's a pleasure to have you. From creating a playground to competing in the daily challenges, there will be wonderful days of math waiting for you.", image: "Mathematically"),
    Item(title: "An award winning app.", description: "Mathematically was submitted to the WWDC22 Swift Student Challenge and was accepted among the 350 accepted apps world-wide.", image: "WWDC22"),
    Item(title: "Need a Walkthrough?", description: "No need to be intimidated. Take the walkthrough if you need to familiarize yourself about the game.", image: "Arrows"),
    Item(title: "Mathematically+", description: "The ultimate premium Mathematically experience, ad-free.", image: "Mathematically+"),
]

    

1 Answers1

0

You're almost there .. you just don't do anything with your currentIndex when it changes. Introduce a ScrollViewReader and an .id so you can scroll to the respective position in your view:

struct ContentView: View {
    
    private let amount = 4
    private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
    
    @State private var currentIndex = 0
    
    var body: some View {
        ScrollViewReader { scrollProxy in // needed to scroll programmatically
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(alignment: .center, spacing: 0) {
                    ForEach(0..<amount) { item in
                        GeometryReader { geometry in
                            ZStack {
                                Rectangle()
                                    .foregroundColor(.gray)
                                    .frame(maxWidth: 350, maxHeight: 300, alignment: .center)
                                    .cornerRadius(16)
                                    .offset(x: 15, y: 50)
                                    .rotation3DEffect(Angle(degrees: (Double(geometry.frame(in: .global).minX) - 30) / -20), axis: (x: 0, y: 1.0, z: 0))
                                
                                VStack {
                                    Text("Hello World!")
                                        .font(.title2)
                                        .bold()
                                        .padding(.bottom, 10)
                                    Text("Item \(item)")
                                }
                                .frame(width: 300)
                                .rotation3DEffect(Angle(degrees: (Double(geometry.frame(in: .global).minX) - 30) / -20), axis: (x: 0, y: 1.0, z: 0))
                                .padding(.leading, 25)
                                .padding(.top, 70)
                            }
                        }
                        .frame(width: 400, height: 500)
                        .offset(x: 10)
                        .id(item) // define id here
                    }
                }
            }
            .onReceive(timer) { _ in
                currentIndex = currentIndex < amount-1 ? currentIndex + 1 : 0
                withAnimation {
                    scrollProxy.scrollTo(currentIndex) // scroll to next .id
                }
            }
        }
    }
}
ChrisR
  • 9,523
  • 1
  • 8
  • 26