1

I'm working on vertical paging, using TabView. I put player code in TabView and rotate it to show vertical paging, but UI breaks.

  • Vertical Pager

struct EpisodeVerticalPager: View {

    let episodes: [Episode]
    @Binding var selectedEpisode: Int
    @Binding var currentPlayer: SimplePlayer?
    @Binding var showControls: Bool

    var body: some View {
        GeometryReader { geo in
            TabView(selection: $selectedEpisode) {
                ForEach(episodes, id: \.id) { ep in
                    EpisodePage(
                        ep: ep,
                        currentPlayer: $currentPlayer,
                        showControls: $showControls
                    )
                    .tag(ep.id ?? 0)
                    .frame(width: geo.size.width, height: geo.size.height)
                }
            }
            .tabViewStyle(.page(indexDisplayMode: .never))
            .frame(width: geo.size.height, height: geo.size.width)
            .rotationEffect(.degrees(90))  // rotate content back
            .ignoresSafeArea()
        }
    }
}

struct EpisodePage: View {

    let ep: Episode
    @Binding var currentPlayer: SimplePlayer?
    @Binding var showControls: Bool

    var body: some View {
        ZStack {
           
            if let p = currentPlayer {
                VerticalPlayerView(player: p, showControls: $showControls)
                    .rotationEffect(.degrees(-90))
            } else {
                Color.black
                    .ignoresSafeArea()
                    .overlay {
                        ProgressView()
                            .progressViewStyle(CircularProgressViewStyle(tint: .white))
                    }
            }
        }
    }
}
  • Image

Player ScreenShot

2
  • The code you pasted appears incomplete. Commented Nov 24 at 11:51
  • @kakaiikaka this is the main code of Pager, other code is for Player only. Commented Nov 24 at 11:55

1 Answer 1

0

Everything breaks because you’re rotating the TabView by 90°, while inside it there’s a horizontal UIScrollView. That’s why your whole layout falls apart. TabView simply isn’t designed to work vertically, and these kinds of hacks almost always lead to issues.

It’s better not to touch TabView at all in this case. Try using a vertical pager like this:

import SwiftUI

struct VerticalPager<Content: View>: View {
    let pageCount: Int
    @Binding var index: Int
    let content: Content
    
    init(pageCount: Int, index: Binding<Int>, @ViewBuilder content: @escaping () -> Content) {
        self.pageCount = pageCount
        self._index = index
        self.content = content()
    }
    
    @GestureState private var dragOffset: CGFloat = 0
    
    var body: some View {
        GeometryReader { geo in
            let height = geo.size.height
            
            VStack(spacing: 0) {
                content
            }
            .frame(width: geo.size.width, height: height * CGFloat(pageCount), alignment: .top)
            .offset(y: -CGFloat(index) * height + dragOffset)
            .animation(.spring(response: 0.35, dampingFraction: 0.85, blendDuration: 0.25), value: index)
            .gesture(
                DragGesture()
                    .updating($dragOffset) { value, state, _ in
                        state = value.translation.height
                    }
                    .onEnded { value in
                        let threshold = height / 3
                        
                        if value.translation.height < -threshold && index < pageCount - 1 {
                            index += 1
                        } else if value.translation.height > threshold && index > 0 {
                            index -= 1
                        }
                    }
            )
        }
    }
}

struct ContentView: View {
    @State private var page = 0
    
    var body: some View {
        VerticalPager(pageCount: 3, index: $page) {
            Color.red
                .overlay(Text("Page 1").font(.largeTitle).foregroundColor(.white))
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            
            Color.green
                .overlay(Text("Page 2").font(.largeTitle).foregroundColor(.white))
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            
            Color.blue
                .overlay(Text("Page 3").font(.largeTitle).foregroundColor(.white))
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
        .ignoresSafeArea()
    }
}

Here we put all pages in a VStack, shift the whole stack up and down by the screen height, and handle the swipe gestures manually. I think it’s a good starting point, and you can refine it further to fit your needs.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.