如何在 SwiftUI 中实现触发 switch case 的左或右 DragGesture()?

Rol*_*tte 3 gesture ios swift swiftui

我在视图中创建了一个 DragGesture,无论用户向左滑动还是向右滑动,它都应该选择一个 @State(Bool)。

问题是只检测到向右滑动。

如何使用 .gesture() 来捕捉用户是在他的屏幕上向左还是向右滑动?

import SwiftUI

struct SwiftUIView: View {

  //MARK: Value to change on swipe gesture
  @State var swipeRight: Bool

  var body: some View {
    VStack {
      //MARK: Value displayed after user swiped
      Text($swipeRight ? "Right" : "Left")
    }
    .gesture(
      DragGesture()
        .onChanged { (value) in
          //MARK: What is it missing here?
          switch value.location.x {
          case ...(-0.5):
            self.swipeRight = false
            print("Swipe Left return false")
          case 0.5...:
            self.swipeRight = true
            print("Swipe Right return true")
          default: ()
          }
    })
}
Run Code Online (Sandbox Code Playgroud)

Moj*_*ini 7

您应该比较新旧位置:

if value.startLocation.x > value.location.x {
    print("Swipe Left")
} else {
    print("Swipe Right")
}
Run Code Online (Sandbox Code Playgroud)

所以你的代码的重构版本将是:

struct ContentView: View {
    enum SwipeHorizontalDirection: String {
        case left, right, none
    }

    @State var swipeHorizontalDirection: SwipeHorizontalDirection = .none { didSet { print(swipeHorizontalDirection) } }

    var body: some View {
        VStack {
            Text(swipeHorizontalDirection.rawValue)
        }
        .gesture(
            DragGesture()
                .onChanged {
                    if $0.startLocation.x > $0.location.x {
                        self.swipeHorizontalDirection = .left
                    } else if $0.startLocation.x == $0.location.x {
                        self.swipeHorizontalDirection = .none
                    } else {
                        self.swipeHorizontalDirection = .right
                    }
        })
    }
}
Run Code Online (Sandbox Code Playgroud)


use*_*232 6

斯威夫特 5,iOS 13

[Mojtaba Hosseini][1] 提出的改进版本在这里。

[1]:https : //stackoverflow.com/users/5623035/mojtaba-hosseini。将枚举和函数放在 ContentView 的主体之前。

enum SwipeHVDirection: String {
    case left, right, up, down, none
}

func detectDirection(value: DragGesture.Value) -> SwipeHVDirection {
if value.startLocation.x < value.location.x - 24 {
            return .left
          }
          if value.startLocation.x > value.location.x + 24 {
            return .right
          }
          if value.startLocation.y < value.location.y - 24 {
            return .down
          }
          if value.startLocation.y > value.location.y + 24 {
            return .up
          }
  return .none
  }
Run Code Online (Sandbox Code Playgroud)

...

在 DragGesture 中调用它。在 onEnded 上调用它以阻止它多次触发。

.gesture(DragGesture()
        .onEnded { value in
        print("value ",value.translation.width)
          let direction = self.detectDirection(value: value)
          if direction == .left {
            // your code here
          }  
        }
      )
Run Code Online (Sandbox Code Playgroud)

显然你需要/可以根据需要添加其他方向......

  • 抱歉,神奇的数字 24 是光标记录滑动所需的行程量。 (2认同)

Sta*_*kis 0

我对@emehex代码做了一个小改进,让你可以选择方向

extension View {
    public func dismissingGesture(tolerance: Double = 24, direction: DragGesture.Value.Direction, action: @escaping () -> ()) -> some View {
        gesture(DragGesture()
            .onEnded { value in
                let swipeDirection = value.detectDirection(tolerance)
                if swipeDirection == direction {
                    action()
                }
            }
        )
    }
}

extension DragGesture.Value {
    func detectDirection(_ tolerance: Double = 24) -> Direction? {
        if startLocation.x < location.x - tolerance { return .left }
        if startLocation.x > location.x + tolerance { return .right }
        if startLocation.y > location.y + tolerance { return .up }
        if startLocation.y < location.y - tolerance { return .down }
        return nil
    }

    enum Direction {
        case left
        case right
        case up
        case down
    }
}

 .dismissingGesture(direction: .right){
                // perform action
            }
Run Code Online (Sandbox Code Playgroud)