在 SwifUI TabView 中禁用滑动手势

问题描述 投票:0回答:3

尝试在

TabView
中实现具有
PageTabView
风格的
SwiftUI
,其中导航仅以编程方式完成,并且所有滑动手势均被禁用。

此解决方案仅部分有效 - 如果您在选择更改时点击屏幕,它仍然会干扰过渡并导致奇怪的效果。此外,如果您用两根手指滚动,该手势仍然会记录下来。我需要一个完全禁用滑动手势的解决方案。

代码:

struct PageViewTest: View {
    @State var selection: Int = 1
    
    var body: some View {
        ZStack {
            Color.green.ignoresSafeArea()
            
            TabView(selection: $selection) {
                Color.red
                    .tag(1)
                    .gesture(DragGesture())
                
                Color.blue
                    .tag(2)
                    .gesture(DragGesture())
                
                Color.yellow
                    .tag(3)
                    .gesture(DragGesture())
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            .animation(.linear, value: selection)
            
            VStack {
                Spacer()
                Button(action: {
                    selection = selection == 3 ? 1 : selection + 1
                }) {
                    Text("next")
                        .foregroundColor(.white)
                        .font(.title)
                }
            }
        }
    }
}

.disabled(true)
设置为
TabView
可以解决此问题,但所有子视图都不再具有交互性。

ios swift swiftui
3个回答
0
投票

这个答案允许在 SwiftUI 中使用自定义手势识别器创建覆盖层。 然后我们需要创建一个不允许手势启动的委托。

所以代码是:

import SwiftUI
import UIKit


struct ContentView: View {
    @State var selection: Int = 1
    let numTabs = 3
    let minDragTranslationForSwipe: CGFloat = 5000

    var body: some View {
        ZStack {
            Color.green.ignoresSafeArea()
            
            TabView(selection: $selection) {
                Color.red
                    .tag(1)
                Color.blue
                    .tag(2)
                Color.yellow
                    .tag(3)
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            .animation(.linear, value: selection)
                .overlay(TouchesHandler())
            
            VStack {
                Spacer()
                Button(action: {
                    selection = selection == 3 ? 1 : selection + 1
                }) {
                    Text("next")
                        .foregroundColor(.white)
                        .font(.title)
                }
            }
        }

    }
}

//just a dummy
class MySwipeGesture: UISwipeGestureRecognizer {

    @objc func noop() {}

    init(target: Any?) {
        super.init(target: target, action: #selector(noop))
    }
}

//this delegate effectively disables the gesure
class MySwipeGestureDelegate: NSObject, UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        false
    }
}

//and the overlay inspired by the answer from the link above
struct TouchesHandler: UIViewRepresentable {

    func makeUIView(context: UIViewRepresentableContext<TouchesHandler>) -> UIView {
        let view = UIView(frame: .zero)
        view.isUserInteractionEnabled = true
        view.addGestureRecognizer(context.coordinator.makeGesture())
        return view;
    }

    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<TouchesHandler>) {
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }

    class Coordinator {
        var delegate: UIGestureRecognizerDelegate = MySwipeGestureDelegate()
        func makeGesture() -> MySwipeGesture {
            delegate = MySwipeGestureDelegate()
            let gr = MySwipeGesture(target: self)
            gr.delegate = delegate
            return gr
        }
    }
    typealias UIViewType = UIView
}

0
投票

这是为了帮助其他人,经过几个小时的研究,我相信以下是使用 github 上的 SwiftUI-Introspec 库的可靠简单的解决方案。如果您只是删除第一个视图上的手势。它让你的问题消失。 :]。您还可以使用前面提到的 Majid 解决方案构建自定义 PagerView 来完全避免此问题。

TabView(selection: $selection) {
    Color.red
        .tag(0)
        .introspectScrollView { scrollView in
            scrollView.gestureRecognizers?.removeAll()
        }
    Color.blue
        .tag(1)
    
    Color.yellow
        .tag(2)
}

0
投票

TabView 末尾使用此行:

.gesture(DragGesture().onChanged({ _ in })).disabled(true)

在您的场景中:

TabView(selection: $selection) {
                Color.red
                    .tag(1)
                    .gesture(DragGesture())
                
                Color.blue
                    .tag(2)
                    .gesture(DragGesture())
                
                Color.yellow
                    .tag(3)
                    .gesture(DragGesture())
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            .gesture(DragGesture().onChanged({ _ in })).disabled(true)
            .animation(.linear, value: selection)
© www.soinside.com 2019 - 2024. All rights reserved.