【问题标题】:Detect DragGesture cancelation in SwiftUI在 SwiftUI 中检测 DragGesture 取消
【发布时间】:2019-11-11 19:16:11
【问题描述】:

所以我有一个添加了 DragGesture 的 Rectangle,并且想要跟踪手势的开始、更改和结束。问题是当我在执行手势时将另一根手指放在 Rectangle 上时,第一个手势停止调用 onChange 处理程序并且不会触发 onEnded 处理程序。 此外,处理程序不会为第二根手指触发。

但是,如果我在没有移除前两个手指的情况下放置第三根手指,该手势的处理程序就会开始触发(依此类推,偶数按下会取消奇数)

这是一个错误吗?有没有办法检测到第一个手势被取消了?

Rectangle()
  .fill(Color.purple)
  .gesture(
    DragGesture(minimumDistance: 0, coordinateSpace: .local)
      .onChanged() { event in
        self.debugLabelText = "changed \(event)"
      }
      .onEnded() { event in
        self.debugLabelText = "ended \(event)"
      }
  )

【问题讨论】:

  • 看起来像一个错误
  • 好像是奇数的手指会触发onEnded,偶数的不会……刚用4根手指和5根手指测试过
  • @krjw,没错!
  • 这个答案是否有助于解决问题:stackoverflow.com/questions/60253490/…

标签: ios swift swiftui gesture


【解决方案1】:

感谢@krjw 提供偶数手指的提示

这似乎是手势框架中的一个问题,它试图检测一堆手势,即使我们没有指定它应该监听它们。

由于文档非常稀少,我们只能真正猜测这里的预期行为和生命周期是什么(恕我直言——这似乎是一个错误)——但它可以解决。

定义一个结构体方法,如

func onDragEnded() {
  // set state, process the last drag position we saw, etc
}

然后将几个手势合二为一,覆盖我们未指定的基础

let drag = DragGesture(minimumDistance: 0)
      .onChanged({ drag in
       // Do stuff with the drag - maybe record what the value is in case things get lost later on 
      })
      .onEnded({ drag in
        self.onDragEnded()
      })

     let hackyPinch = MagnificationGesture(minimumScaleDelta: 0.0)
      .onChanged({ delta in
        self.onDragEnded()
      })
      .onEnded({ delta in
        self.onDragEnded()
      })

    let hackyRotation = RotationGesture(minimumAngleDelta: Angle(degrees: 0.0))
      .onChanged({ delta in
        self.onDragEnded()
      })
      .onEnded({ delta in
        self.onDragEnded()
      })

    let hackyPress = LongPressGesture(minimumDuration: 0.0, maximumDistance: 0.0)
      .onChanged({ _ in
        self.onDragEnded()
      })
      .onEnded({ delta in
        self.onDragEnded()
      })

    let combinedGesture = drag
      .simultaneously(with: hackyPinch)      
      .simultaneously(with: hackyRotation)
      .exclusively(before: hackyPress)

/// The pinch and rotation may not be needed - in my case I don't but 
///   obviously this might be very dependent on what you want to achieve

simultaneouslyexclusively 可能有更好的组合,但至少对于我的用例(类似于操纵杆的东西)来说,这似乎正在完成这项工作

还有一个GestureMask 类型可能已经完成了这项工作,但没有关于它如何工作的文档。

【讨论】:

    【解决方案2】:

    一种解决方案是使用@GestureState 属性来跟踪拖动当前是否正在运行。取消手势时,状态会自动重置为 false。

    struct DragSampleView: View {
        @GestureState private var dragGestureActive: Bool = false
        @State var dragOffset: CGSize = .zero
    
        var draggingView: some View {
            Text("DRAG ME").padding(50).background(.red)
        }
    
        var body: some View {
            ZStack {
                Color.blue.ignoresSafeArea()
                draggingView
                    .offset(dragOffset)
                    .gesture(DragGesture()
                        .updating($dragGestureActive) { value, state, transaction in
                            state = true
                        }
                        .onChanged { value in
                            print("onChanged")
                            dragOffset = value.translation
                        }.onEnded { value in
                            print("onEnded")
                            dragOffset = .zero
                        })
                    .onChange(of: dragGestureActive) { newIsActiveValue in
                        if newIsActiveValue == false {
                            dragCancelled()
                        }
                    }
            }
        }
    
        private func dragCancelled() {
            print("dragCancelled")
            dragOffset = .zero
        }
    }
    
    struct DragV_PreviewProvider: PreviewProvider {
        static var previews: some View {
            DragSampleView()
        }
    }
    

    https://developer.apple.com/documentation/swiftui/draggesture/updating(_:body:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-05
      • 1970-01-01
      相关资源
      最近更新 更多