尝试在
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
可以解决此问题,但所有子视图都不再具有交互性。
这个答案允许在 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
}
这是为了帮助其他人,经过几个小时的研究,我相信以下是使用 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)
}
在 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)