Vertical Paging in SwiftUI
Asked Answered
E

3

6

I'm creating a vertical paging view via TabView following this

Everything is perfect except the strange right margin as highlighted in pic below.

Here is the code I use. Appreciate it if anyone could point out the root cause.

enter image description here

import SwiftUI

fileprivate struct VCompatibleTabView<Content: View>: View {
    let proxy: GeometryProxy
    let content: Content
    
    init(proxy: GeometryProxy, @ViewBuilder content: () -> Content) {
        self.proxy = proxy
        self.content = content()
    }
    
    var body: some View {
        if #available(iOS 15.0, *) {
            // Credit to Gary Tokmen for this bit of Geometry Reader code: https://blog.prototypr.io/how-to-vertical-paging-in-swiftui-f0e4afa739ba
            TabView {
                content
                .rotationEffect(.degrees(-90)) // Rotate content
                .frame(
                    width: proxy.size.width,
                    height: proxy.size.height
                )
            }
            .frame(
                width: proxy.size.height, // Height & width swap
                height: proxy.size.width
            )
            .rotationEffect(.degrees(90), anchor: .topLeading) // Rotate TabView
            .offset(x: proxy.size.width) // Offset back into screens bounds
            .tabViewStyle(
                PageTabViewStyle(indexDisplayMode: .never)
            )
        } else {
            ScrollView(.vertical, showsIndicators: false) {
                LazyVStack(spacing: 0) {
                    content
                }
            }
            .frame(
                width: proxy.size.width,
                height: proxy.size.height)        }
    }
}

struct BBYouView: View {

    var body: some View {
        ZStack {
            GeometryReader { proxy in
                VCompatibleTabView(proxy: proxy) {
                    ForEach(0..<3, id: \.self) { item in
                        Rectangle().fill(Color.pink)
                        .frame(
                            width: proxy.size.width,
                            height: proxy.size.height
                        )
                    }
                }
            }
        }
        .background(Color.yellow)
    }


}
Endothecium answered 25/2, 2022 at 13:27 Comment(2)
Does this answer your question? SwiftUI TabView with PageTabViewStyle in Landscape on device with safeArea adding odd leading edge insetGratification
Hey...any update on this issue?Icken
C
4

Horizontal/Vertical paging in iOS 17

From iOS 17, you don't need to do the hack of rotating the tab view and you can enable the paging behavior by applying the following modifier on the ScrollView:

.scrollTargetBehavior(.paging)

So anything inside the ScrollView like a simple ForEach inside a stack would be paging as desired. This works for both horizontal and vertical scrollviews.

Cero answered 16/6, 2023 at 11:4 Comment(1)
Montana, I am using the Tab View hack of rotating, I was going to look into switching in iOS 17, but I was trying to find out if the .scrollTargetBehavior in iOS 17 give you the ability to advance to a certain age and/or know the current page your on? I know this is an old post, but I am taking a shot and hoping you would know the answer. Thanks for any helpHedveh
E
3

There is iOS17 modifier .scrollTargetBehavior(.paging), for older versions this hack should work:

import SwiftUIIntrospect

GeometryReader { proxy in
    ScrollView {
        LazyVStack(spacing: 0) {
            ForEach([Color.red, Color.green, Color.blue], id: \.self) { color in
                color.frame(proxy.size)
            }
        }
    }
    .introspect(.scrollView, on: .iOS(.v15, .v16, .v17)) { sv in
        sv.isPagingEnabled = true
    }
}
Eggcup answered 18/8, 2023 at 11:44 Comment(0)
H
0

Try adding the scaledToFill() modifier on the content view within the TabView. That modifier scales the view to fill its parent. I've found that it works when the content view is an AsyncImage or Image view and it should work with any single views. However, with a horizontal TabView and it had the same issue with the strange margin on the right edge of the screen.

Example code below:

  TabView {
                    content.scaledToFill()
                    .rotationEffect(.degrees(-90)) // Rotate content
                    .frame(
                        width: proxy.size.width,
                        height: proxy.size.height
                    )
                }
                .frame(
                    width: proxy.size.height, // Height & width swap
                    height: proxy.size.width
                )
                .rotationEffect(.degrees(90), anchor: .topLeading) // Rotate TabView
                .offset(x: proxy.size.width) // Offset back into screens bounds
                .tabViewStyle(
                    PageTabViewStyle(indexDisplayMode: .never)
                )
}
Hydrograph answered 13/7, 2024 at 18:39 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.