SwiftUI Page样式TabView拖拽手势onEnded不触发问题求助
Page样式TabView监听索引变化与拖拽结束时机问题
我有一个采用Page样式的TabView,需要监听其索引变化以及用户手指离开屏幕的时机。尝试使用DragGesture实现,但遇到问题:拖拽手势的onChanged方法在开始拖拽时会触发,但onEnded方法仅在上下拖拽时才会被调用,左右拖拽时无法触发。代码如下:
struct TestView: View { @State var currentIndex = 0 var body: some View { TabView(selection: $currentIndex) { Color.red .tag(0) Color.blue .tag(1) } .tabViewStyle(.page) .frame(height: 400) .onChange(of: currentIndex) { newValue in print("Current Index Changed") } .gesture( DragGesture() .onChanged({ x in print("Gesture Changed") }) .onEnded({ x in print("Gesture Ended") }) ) } }
解决方案
方法1:用simultaneousGesture替代gesture
问题核心是Page样式的TabView自带左右拖拽手势,直接用.gesture()会导致自定义手势和内置手势竞争,左右拖拽时内置手势优先响应,使得自定义手势的onEnded无法触发。改用.simultaneousGesture()可以让两个手势同时被识别,完美解决这个问题:
struct TestView: View { @State var currentIndex = 0 var body: some View { TabView(selection: $currentIndex) { Color.red .tag(0) Color.blue .tag(1) } .tabViewStyle(.page) .frame(height: 400) .onChange(of: currentIndex) { newValue in print("Current Index Changed") } // 替换为simultaneousGesture .simultaneousGesture( DragGesture() .onChanged({ _ in print("Gesture Changed") }) .onEnded({ _ in print("Gesture Ended") }) ) } }
方法2:区分拖拽中的索引变化与拖拽结束后的稳定状态
如果需要在手指离开且页面完全切换完成后执行逻辑,可以增加状态标记区分拖拽状态:
struct TestView: View { @State var currentIndex = 0 @State var isDragging = false var body: some View { TabView(selection: $currentIndex) { Color.red .tag(0) Color.blue .tag(1) } .tabViewStyle(.page) .frame(height: 400) .onChange(of: currentIndex) { newValue in print("Current Index Changed") // 仅在拖拽结束后触发后续逻辑 if !isDragging { print("Page settled after drag end") } } .simultaneousGesture( DragGesture() .onChanged({ _ in isDragging = true print("Gesture Changed") }) .onEnded({ _ in isDragging = false print("Gesture Ended") }) ) } }
方法3:自定义Page滚动容器(完全掌控手势)
如果对原生TabView的手势限制不满意,可以用ScrollView自己实现Page样式,这样能完全控制所有手势回调:
struct CustomPageTabView: View { @State var currentIndex = 0 let colors: [Color] = [.red, .blue] var body: some View { ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 0) { ForEach(colors.indices, id: \.self) { index in colors[index] .frame(width: UIScreen.main.bounds.width) } } } .scrollTargetLayout() .scrollPosition(id: $currentIndex) .frame(height: 400) .onChange(of: currentIndex) { newValue in print("Current Index Changed") } .gesture( DragGesture() .onEnded({ _ in print("Gesture Ended") }) ) } }
内容的提问来源于stack exchange,提问作者Luis Ramirez
相关产品推荐
相关产品推荐

