如何实现在SwiftUI中触发开关情况的左右DragGesture()?

时间:2019-11-29 17:42:16

标签: ios swift swiftui gesture

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

3 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:2)

我认为上述方向相反?还是我误解了向左和向右滑动。无论如何,这是使用视图修饰符的进一步改进。您只需在.onSwipe {方向...}上查看即可。

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

答案 2 :(得分:0)

您应该比较旧位置和新位置:

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