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

ibrsph3r  于 2023-11-16  发布在  Swift
关注(0)|答案(6)|浏览(130)

我已经在视图中创建了一个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: ()
          }
    })
}

字符串

r1zhe5dt

r1zhe5dt1#

Swift 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
  }

字符串
...
在DragGesture中调用它。在onEnded上调用它以阻止它多次发射。

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


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

n6lpvg4x

n6lpvg4x2#

你应该比较一下旧的和新的位置:

if value.startLocation.x > value.location.x {
    print("Swipe Left")
} else {
    print("Swipe Right")
}

字符串
所以你的代码的重构版本应该是:

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
                    }
        })
    }
}

ny6fqffe

ny6fqffe3#

我想上面的方向是颠倒的?或者我误解了左右滑动。无论如何,这里有一个使用视图修饰符的进一步改进。你可以在.onSwipe { direction in.}到你的视图。

struct SwipeModifier: ViewModifier {
    let action: ((UISwipeGestureRecognizer.Direction) -> Void)?

    init(perform action: ((UISwipeGestureRecognizer.Direction) -> Void)? = nil) {
        self.action = action
    }
        
    func body(content: Content) -> some View {
        content
            .gesture(DragGesture(minimumDistance: 24.0, coordinateSpace: .local)
                        .onEnded { value in
                            guard let action = action else {
                                return
                            }
                            if value.startLocation.x > value.location.x {
                                action(.left)
                            } else if value.startLocation.x < value.location.x {
                                action(.right)
                            } else if value.startLocation.y > value.location.y {
                                action(.down)
                            } else if value.startLocation.y < value.location.y {
                                action(.up)
                            }
                        })
    }
}

extension View {
    public func onSwipe(perform action: ((UISwipeGestureRecognizer.Direction) -> Void)? = nil) -> some View {
        return self.modifier(SwipeModifier(perform: action))
    }
}

字符串

dgiusagp

dgiusagp4#

扩展DragGesture.Value

import SwiftUI

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
    }
}

字符串
View添加dismissingGesture方法:

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


示例用法:

struct DismissingGesture_Previews: PreviewProvider {
    static var previews: some View {
        Preview()
    }
    
    struct Preview: View {
        var body: some View {
            NavigationView {
                NavigationLink {
                    Destination()
                } label: {
                    Text("Go")
                }
            }
        }
    }
    
    struct Destination: View {
        @Environment(\.dismiss) private var dismiss
        
        var body: some View {
            ZStack {
                Color.yellow.edgesIgnoringSafeArea(.all)
                Text("Nothing")
            }
            .dismissingGesture {
                dismiss()
            }
            .navigationBarHidden(true)
        }
    }
}

wpx232ag

wpx232ag5#

我在@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
            }

字符串

62lalag4

62lalag46#

这里有一个非常直接的例子,它检测到一个超过一定最小距离的阻力,然后决定哪个方向的阻力最大。

  • 确定阻力是垂直还是水平
  • 确定阻力是向上/向下还是向左/向右。
.gesture(DragGesture(minimumDistance: 80, coordinateSpace: .local)

     .onEnded({ value in

         let yChange = abs(value.startLocation.y - value.location.y)
         let xChange = abs(value.startLocation.x - value.location.x)

         if (yChange > xChange) {

             if (value.startLocation.y > value.location.y) {
                 print("up")
             } else {
                 print("down")
             }

         } else {

             if (value.startLocation.x > value.location.x) {
                 print("left")
             } else {
                 print("right")
             }

         }
     })
 )

字符串

相关问题