【问题标题】:Calculate velocity of DragGesture计算 DragGesture 的速度
【发布时间】:2019-07-26 15:16:33
【问题描述】:

我想提取 DragGesture 的速度以用于弹簧动画的 initialVelocity 参数。我正在尝试创建一个可移动的卡片,它具有类似 Apple Maps 应用程序中的响应式弹簧动画。

我尝试通过将拖动平移的高度除以拖动手势的总时间来计算速度。

v_abs = abs(Double(drag.translation.height / CGFloat(drag.time.timeIntervalSinceNow)))

问题是当用户开始拖动时,他们可能会在轻弹和释放之前减慢拖动速度,这会导致速度非常慢,因为已经过了很长一段时间。如果可能的话,我只想使用拖动手势最后几毫秒的数据来计算速度。

【问题讨论】:

  • 这无关。我正在使用 DragGesture,它是 SwiftUI 的一部分。我没有使用 UIPanGestureRecognizer。

标签: ios swift swiftui


【解决方案1】:

通过将最后一个拖动位置存储为状态,然后在调用 onEnded 时使用它来推导速度值,我已经能够获得相当不错的拖动速度值。

struct MyComponent: View {

    @State var lastDragPosition: DragGesture.Value?

    var body: some View {
        VStack{
            SomeOtherView()
        }.gesture(
            DragGesture().onChanged { value in
                self.lastDragPosition = value
            }
            .onEnded { value in
                let timeDiff = value.time.timeIntervalSince(self.lastDragPosition!.time)
                let speed:CGFloat = CGFloat(value.translation.height - self.lastDragPosition!.translation.height) / CGFloat(timeDiff)

                if(speed > 500) {
                    //Do Something
                }
            }
        )
    }
}

【讨论】:

    【解决方案2】:

    您只需使用 DragGesture.Value 已经提供的 predictedEndLocation 即可计算隐含速度而无需保持中间状态:

    DragGesture()
    .onChanged { value in 
        // Do something
    }
    .onEnded { value in
        let velocity = CGSize(
            width:  value.predictedEndLocation.x - value.location.x,
            height: value.predictedEndLocation.y - value.location.y
        )
    
        // Example
    
        if velocity.height > 500.0 {
            // Moving down fast
        }
    }
    

    【讨论】:

      【解决方案3】:

      最后,我得到了这样的速度。 (不知道为什么打印值时无法访问 DragGesture.value 的速度)

      struct ContentView: View {
      
          @State private var previousDragValue: DragGesture.Value?
      
          func calcDragVelocity(previousValue: DragGesture.Value, currentValue: DragGesture.Value) -> (Double, Double)? {
              let timeInterval = currentValue.time.timeIntervalSince(previousValue.time)
      
              let diffXInTimeInterval = Double(currentValue.translation.width - previousValue.translation.width)
              let diffYInTimeInterval = Double(currentValue.translation.height - previousValue.translation.height)
      
              let velocityX = diffXInTimeInterval / timeInterval
              let velocityY = diffYInTimeInterval / timeInterval
              return (velocityX, velocityY)
          }
      
          var body: some View {
              return
                  VStack {
                      …
                  }
                  .gesture(DragGesture().onChanged {value in
                      if let previousValue = self.previousDragValue {
                          // calc velocity using currentValue and previousValue
                          print(self.calcDragVelocity(previousValue: previousValue, currentValue: value))
                      }
                      // save previous value
                      self.previousDragValue = value
                  }
          }
      }
      

      【讨论】:

        【解决方案4】:

        说实话,你甚至不需要速度。只需使用DragGesture.ValuepredictedEndTranslation

        【讨论】:

        • 长距离慢速拖动的 predictEndTranslation 将返回与快速但短距离相同的大值,因此对于提供拖动速度没有用处。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多