SwiftUI ScrollView peeking next and previous item

59 Views Asked by At

I'm going to create a ScrollView that contains 10 RoundedRectangle() in it, I want it to only show one rectangle on screen but it also can peeking next and previous item a little, to remind user there's other rectangle they can scroll.
I added with a .scrollTargetLayout()and also .scrollTargetLayoutBehavior(.viewAligned), also, each item in ScrollView was added a .containerRelativeFrame(_:) to make sure there's only one rectangle will appear on the screen, and the last one is .scrollPosition(id: ) to control what rectangle should appear.
but it seems that there's one rectangle on the screen, so how should I change my code to let the next and previous item can be peeked?
these are my code below:

struct CardTheme: View {
    @State private var scrollID: Int? = 0
    
    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack {
                ForEach(0..<10, id: \.self) { i in
                    RoundedRectangle(cornerRadius: 25)
                        .frame(width: 280, height: 450)
                        .containerRelativeFrame(.horizontal, count: 1, spacing: 16)
                }
            }
            .scrollTargetLayout()
        }
        .scrollTargetBehavior(.viewAligned)
        .scrollPosition(id: $scrollID)
    }
}

The result I want to see is like this
This is mine

I have tried change the number of count in this code: .containerRelativeFrame(.horizontal, count: 1, spacing: 16) and deleted frame(), while the number was more than 3, I could see the next item on the screen
the preview
changed code

1

There are 1 best solutions below

2
MatBuompy On BEST ANSWER

If you use containerRelativeFrame you will always end up occupying the entire view as far as I know. So, what I've done is that I used a GeometryReader to get the size of the ScrollView subtracted the width of your RoundedRectangle dividing it all by 2 and applied its value as an horizontal padding to the HStack wrapped around your Rectangle:

struct CardTheme: View {
    @State private var scrollID: Int? = 0
    
    var body: some View {
        GeometryReader { proxy in
            let size = proxy.size
            ScrollView(.horizontal, showsIndicators: false) {
                HStack {
                    ForEach(0..<10, id: \.self) { i in
                        RoundedRectangle(cornerRadius: 25)
                            .frame(width: 280, height: 450)
                            /// Remove this line
                            //.containerRelativeFrame(.horizontal, count: 1, spacing: 16)
                    }
                }
                /// 280 is the width of your item. Change it as needed.
                .padding(.horizontal, (size.width - 280) / 2)
                .scrollTargetLayout()
            }
            .scrollTargetBehavior(.viewAligned)
            .scrollPosition(id: $scrollID)
        }
    }
}

If you want better customisation or control over this, you can check out this project and getting the CoverFlowView file from it, which creates a customisable paged ScrollView just like yours but that is much more flexible since you can give it any spacing you want between items etc, which I made thanks to YouTuber Kavsoft, so credtis to him, which I also used in a modified version with some gestures in an answere here.

Here's the result with just the code I posted above:

Peeking ScrollView

Let me know your thoughts.