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

Posted

技术标签:

【中文标题】如何在 SwiftUI 中实现触发 switch case 的左或右 DragGesture()?【英文标题】:How to implement a left or right DragGesture() that trigger a switch case in SwiftUI? 【发布时间】:2019-11-29 17:42:16 【问题描述】:

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

【问题讨论】:

【参考方案1】:

Swift 5、ios 13

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

[1]:https://***.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
            
        
      )

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

【讨论】:

每个 if 语句的 24 个值是多少?我使用了这个解决方案,它非常适合左导航滑动手势功能。 魔幻数字 24,抱歉,这是光标注册滑动所需的行程量。【参考方案2】:

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

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
                    
        )
    

【讨论】:

【参考方案3】:

我认为上面的方向是颠倒的?或者我误解了左右滑动。无论如何,这是使用视图修饰符的进一步改进。您可以在 .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))
    

【讨论】:

这段代码有问题,不会产生预期的效果。如果用户现在尝试向上拖动并且他们的手指在该拖动期间向左或向右移动了 1 个点,则只要最小拖动距离为 24.0,向左或向右条件将评估为真。您需要按照上述解决方案在value.location 上保留减数/加数,以防止这种不良行为。

以上是关于如何在 SwiftUI 中实现触发 switch case 的左或右 DragGesture()?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中实现 MVVM 模式?视图不会重新渲染

SwiftUI:如何在 macOS 应用程序中实现编辑菜单

如何在 Kotlin 中实现 switch-case 语句

如何在 swiftui 中实现 struct View 上的 var 类 ObservableObject

如何在 SwiftUI 中的 WatchOS 中实现 handleUserActivity?

如何在不中断删除的情况下在 SwiftUI 中实现 TextField 列表