Categories
SwiftUI

How to create Page View in SwiftUI

Please check Majid’s tutorial on making a PagerView. This tutorial uses Majid’s code with some small changes. If you want to understand how to create the PagerView using @ViewBuilder visit swiftwithmajid.com


Code Snippet Changes

What I’m changing

  • Adding dots to indicate the number of pages inside the view.
  • Making the swipe gesture weaker.

Here is the the container that will hold all of our pages. For explanation, please visit Majid’s page. Adjust the WeakGesture variable’s value to your liking. Below I have it alternating between 100 and -100 depending on the swipe direction.

struct PagesContainer <Content : View> : View {
    let contentCount: Int
    @State var index: Int = 0
    let content: Content
    @GestureState private var translation: CGFloat = 0
    
    init(contentCount: Int, @ViewBuilder content: () -> Content) {
        self.contentCount = contentCount
        self.content = content()
    }
    
    var body: some View {
        GeometryReader { geometry in
            VStack {
                HStack (spacing: 0){
                    self.content
                        .frame(width: geometry.size.width)
                }
                .frame(width: geometry.size.width, alignment: .leading)
                .offset(x: -CGFloat(self.index) * geometry.size.width)
                .offset(x: self.translation)
                .animation(.interactiveSpring())
                .gesture(
                    DragGesture().updating(self.$translation) { value, state, _ in
                        state = value.translation.width
                    }.onEnded { value in
                        var weakGesture : CGFloat = 0
                        if value.translation.width < 0 {
                            weakGesture = -100
                        } else {
                            weakGesture = 100
                        }
                        let offset = (value.translation.width + weakGesture) / geometry.size.width
                        let newIndex = (CGFloat(self.index) - offset).rounded()
                        self.index = min(max(Int(newIndex), 0), self.contentCount - 1)
                    }
                )
                HStack {
                    ForEach(0..<self.contentCount) { num in
                        Circle().frame(width: 10, height: 10)
                            .foregroundColor(self.index == num ? .primary : Color.secondary.opacity(0.5))
                    }
                }
            }
        }
    }
}

You can use it inside your ContentView as below, Provide the PagesContainer the number of contents you have inside it then add the view elements.

struct ContentView: View {
    var body: some View {
        PagesContainer(contentCount: 4) {
            RoundedRectangle(cornerRadius: 20)
                .foregroundColor(Color.green.opacity(0.3))
                .padding()
            RoundedRectangle(cornerRadius: 20)
                .foregroundColor(Color.yellow.opacity(0.3))
                .padding()
            RoundedRectangle(cornerRadius: 20)
                .foregroundColor(Color.red.opacity(0.3))
                .padding()
            RoundedRectangle(cornerRadius: 20)
                .foregroundColor(Color.blue.opacity(0.3))
                .padding()
        }
        .frame(width: 300, height: 400)
    }
}

Pages in SwiftUI

Leave a Reply

Your email address will not be published. Required fields are marked *