如何在 SwiftUI 的滚动视图中添加垂直向上滑动手势(以转到不同的视图)

How do I add a vertical swipe up gesture(to go to a different view) in a scrollview in SwiftUI

我设计了一个 SwiftUI 视图,它是一个滚动视图。现在我需要向它添加一个垂直滑动手势,将它带到不同的视图。我尝试使用 tabView 并为其添加 -90 度的旋转效果。但这也旋转了我的原始视图,这不是我想要的。我在处理将滚动视图向上滑动到新视图的 SwiftUI 中找不到任何相关帮助。 这是我的代码..

我用它实现的垂直滑动。但我的观点得到了旋转。设置其他角度会以某种方式消失视图。我是SwiftUI新手,卡了一个星期了1

GeometryReader { proxy in
        TabView {
            ScrollView {
                VStack(alignment: .center) {
                    ZStack(alignment: .leading) {
                        Image("Asset 13").resizable().frame(width: percentWidth(percentage: 100), height: percentHeight(percentage: 50), alignment: .top)
                        HStack {
                            Spacer()
                            Image("Asset 1")//.padding(.bottom, 130)
                            Spacer()
                        }.padding(.bottom, 150)
                        
                        HStack {
                            VStack(spacing:2) {
                                Text("followers").foregroundColor(.white).padding(.leading, 20)
                                HStack {
                                    Image("Asset 3")
                                    Text("10.5k").foregroundColor(.white)
                                }
                            }
                            Spacer()
                            VStack {
                                Image("Asset 10").padding(.trailing)
                                Text("300K Review ").foregroundColor(.white)
                            }
                            
                        }.background(Image("Asset 2").resizable().frame(width: percentWidth(percentage: 100), height: percentHeight(percentage: 6), alignment: .leading))
                            .padding(.top, 410)
                        HStack {
                            Spacer()
                            Image("Asset 14").resizable().frame(width: percentWidth(percentage: 50), height: percentHeight(percentage: 25), alignment: .center)
                            Spacer()
                        }.padding(.top, 390)
                        
                        
                    }
                    VStack(spacing: 4) {
                        Text("Karuna Ahuja | Yoga Instructor").font(Font.custom(FontName.bold, size: 22))
                        Text("12 Years of Experience with Bhartiya Yog Sansthan").tracking(-1).font(Font.custom(FontName.light, size: 16)).opacity(0.4)
                    }
                    Divider()
                    HStack {
                        ZStack {
                            Image("Asset 6").resizable().frame(width: percentWidth(percentage: 30), height: percentHeight(percentage: 12), alignment: .center)
                            VStack {
                                Image("Asset 5").resizable().frame(width: percentWidth(percentage: 8), height: percentHeight(percentage: 4), alignment: .center)
                                Text("245").font(Font.custom(FontName.bold, size: 16))
                                Text("Video").font(Font.custom(FontName.medium, size: 16)).opacity(0.5)
                            }
                        }
                        
                        ZStack {
                            Image("Asset 6").resizable().frame(width: percentWidth(percentage: 30), height: percentHeight(percentage: 12), alignment: .center)
                            VStack {
                                Image("Asset 7").resizable().frame(width: percentWidth(percentage: 8), height: percentHeight(percentage: 4), alignment: .center)
                                Text("45").font(Font.custom(FontName.bold, size: 16))
                                Text("Live Class").font(Font.custom(FontName.medium, size: 16)).opacity(0.5)
                            }
                        }
                        
                        ZStack {
                            Image("Asset 6").resizable().frame(width: percentWidth(percentage: 30), height: percentHeight(percentage: 12), alignment: .center)
                            VStack {
                                Image("Asset 9").resizable().frame(width: percentWidth(percentage: 8), height: percentHeight(percentage: 4), alignment: .center)
                                Text("245").font(Font.custom(FontName.bold, size: 16))
                                Text("Sessions").font(Font.custom(FontName.medium, size: 16)).opacity(0.5)
                            }
                        }
                    }
                    Divider()
                    Text("Shine bright so that your light leads other. I'm a fitness junkie, high-energy yoga instructor. Let's make fitness FUN!").font(Font.custom(FontName.normal, size: 16)).tracking(-1).opacity(0.7).padding([.leading,.trailing], 6)
                    VideoPlayer(player: AVPlayer(url: videoUrl))
                        .frame(height: 320)
                    
                    Spacer()
                }.gesture(DragGesture(minimumDistance: 20, coordinateSpace: .global)
                    .onEnded { value in
                        let horizontalAmount = value.translation.width as CGFloat
                        let verticalAmount = value.translation.height as CGFloat
                        
                        if abs(horizontalAmount) > abs(verticalAmount) {
                            print(horizontalAmount < 0 ? "left swipe" : "right swipe")
                        } else {
                            print(verticalAmount < 0 ? "up swipe" : "down swipe")
                        }
                    })
            }.edgesIgnoringSafeArea(.all)
                .ignoresSafeArea()
            Text("this")
            Text("this")
            Text("this")
            
            //                ForEach(colors, id: \.self) { color in
            //                    color // Your cell 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)
        )
    }

我看到的唯一纯 SwiftUI 方式是自己实现 ScrollView,这并不太复杂。这个例子有两个视图在彼此之上。如果将第一个视图向上拖动到屏幕中间以外的位置,它会滑开以显示第二个视图。

struct ContentView: View {
    
    @State private var offset = CGFloat.zero
    @State private var dragOffset = CGFloat.zero
    @State private var viewHeight = CGFloat.zero
    
    var body: some View {
        
        GeometryReader { fullgeo in
            ZStack(alignment: .top) {
                
                SecondView()
                // necessary for second view to resize individually
                    .frame(height: fullgeo.size.height)
                
                ScrollingView()
                    .overlay( GeometryReader { geo in Color.clear.onAppear { viewHeight = geo.size.height }})
                
                    .offset(y: offset + dragOffset)
                
                    .gesture(DragGesture()
                        .onChanged { value in
                            dragOffset = value.translation.height
                        }
                        .onEnded { value in
                            withAnimation(.easeOut) {
                                dragOffset = .zero
                                offset += value.predictedEndTranslation.height
                                
                                // if bottom dragged higher than 50% of screen > second view
                                if offset < -(viewHeight - fullgeo.size.height/2) {
                                    dragOffset = -viewHeight
                                    return
                                }
                                
                                // else constrain to top / bottom of ScrollingView
                                offset = max(min(offset, 0), -(viewHeight - fullgeo.size.height))
                                
                                
                            }
                        }
                    )
            }
        }
    }
}

struct ScrollingView: View {
    var body: some View {
        VStack {
            Text("View Top").font(.headline)
            ForEach(0..<10) { _ in
                Text("Content")
                    .frame(width: 200, height: 100)
                    .background(.white)
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(.gray)
    }
}

struct SecondView: View {
    var body: some View {
        Text("View Bottom").font(.headline)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(.orange)
    }
}