简体   繁体   English

SwiftUI 处理带有释放动作的 onTapGesture 和 onLongPressGesture 的按钮/视图

[英]SwiftUI handling button/view with onTapGesture and onLongPressGesture with a release action

I have a view that has both onTapGesture and onLongPressGesture simultaneously.我有一个同时具有 onTapGesture 和 onLongPressGesture 的视图。 The issue is that the implementation of my onLongPressGesture prevents onTapGesture from ever being called.问题是我的 onLongPressGesture 的实现阻止了 onTapGesture 被调用。

Here is some code这是一些代码

View()
      .onTapGesture {
           action_1
       }
      .onLongPressGesture(minimumDuration: 0.5, maximumDistance: 10, pressing: {
                                    pressing in
                                    self.isPressing = pressing
                                    if (pressing) {action_2}
                                    if !pressing {action_3}
                                }, perform: {})

The pressing argument in.onLongPressGesture detects if a user is pressing the view/button, and will always perform the.onLongPressGesture, regardless of what the minimumDuration is. pressing 参数 in.onLongPressGesture 检测用户是否按下视图/按钮,并且将始终执行 the.onLongPressGesture,无论 minimumDuration 是多少。

Edit编辑

Snapchat shutter where you can tap to take a picture, hold the button to start recording a video, then release the button to stop recording the video.您可以点击Snapchat 快门拍照,按住按钮开始录制视频,然后松开按钮停止录制视频。 That is why there are three actions that need to be performed.这就是为什么需要执行三个操作的原因。

This is tricky.这很棘手。 Here's what I did:这是我所做的:

  1. onTapGesture , for the tap gesture onTapGesture ,用于点击手势
  2. LongPressGesture , for a 0.5 second delay. LongPressGesture ,延迟 0.5 秒。 Once the 0.5 seconds is over ( .onEnded ), start the recording.一旦 0.5 秒结束( .onEnded ),开始录制。
  3. DragGesture , for observing when the finger lift off the screen. DragGesture ,用于观察手指何时离开屏幕。 When this happens, stop the recording.发生这种情况时,请停止录制。
struct ContentView: View {
    
    /// for visual indicators
    @State var recording = false
    @State var tapped = false
    
    var body: some View {
        let longPressDrag = LongPressGesture(minimumDuration: 0.5) /// 2.
            .onEnded { _ in /// 0.5 seconds is over, start recording
                print("Long press start")
                recording = true
            }
            .sequenced(before: DragGesture(minimumDistance: 0)) /// 3.
            .onEnded { _ in /// finger lifted, stop recording
                print("Long press release")
                recording = false
            }
        
        Circle()
            .fill(recording ? Color.red : Color.blue)
            .opacity(tapped ? 0.5 : 1)
            .frame(width: 100, height: 100)
            
            .onTapGesture { /// 1.
                print("Tapped")
                
                tapped = true
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { tapped = false }
            }
            .gesture(longPressDrag)

    }
}

Result:结果:

Snapchat 风格的按钮

Old answer: The pressing parameter isn't for performing actions like action_2 .旧答案: action_2 pressing的操作。 You can, but it's more commonly used for changing @State , so for example highlighting the view in green when it's pressed.你可以,但它更常用于更改@State ,例如在按下视图时以绿色突出显示视图。 You can find more information in the community documentation .您可以在社区文档中找到更多信息。

Instead, what you probably want is to call your action ( action_2 / print("long") ) in the perform closure.相反,您可能想要的是在perform闭包中调用您的操作( action_2 / print("long") )。

struct ContentView: View {
    var body: some View {
        Text("Hi")
            .font(.title)
            .onTapGesture {
                print("tap")
            }
            .onLongPressGesture(minimumDuration: 0.5, maximumDistance: 10) {
                print("long")
            }
    }
}

Result:结果:

点击和长按都可以工作

XCode 14. Swift 5 I have added both gesture to Image View. XCode 14. Swift 5我已将这两个手势添加到图像视图中。 On tap gesture image will be scale and unscale.点击手势图像将缩放和取消缩放。 On LongPressGesture image bg color will change.在 LongPressGesture 上图像背景颜色会改变。 Provide count: 2 to make it doubleTapGesture.提供 count: 2 使其成为 doubleTapGesture。

struct ContentView: View {
// MARK: - Property

@State private var isAnimating: Bool = false
@State private var imageScale: CGFloat = 1
@State private var shadowColor: Color = .black

// MARK: - Content
var body: some View {
    NavigationView {
        ZStack {
            Image("magazine-front-cover")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .cornerRadius(8)
                .padding()
                .shadow(color: shadowColor, radius: 22, x: 2, y: 2)
                .opacity(isAnimating ? 1 : 0)
                .animation(.linear(duration: 1), value: isAnimating)
                .scaleEffect(imageScale)
            // MARK: - 1. Tap Gesture
                .onTapGesture(count: 1, perform: {
                    if imageScale == 1 {
                        withAnimation(.spring()) {
                            imageScale = 5
                        }
                    } else {
                        withAnimation(.spring()) {
                            imageScale = 1
                        }
                    }
                })
            // MARK: - 2. LongPress Gesture
                .onLongPressGesture(perform: {
                    if shadowColor == .black {
                        shadowColor = .green
                    } else {
                        shadowColor = .black
                    }
                })
        }
        .ignoresSafeArea(edges: .all)
        .navigationTitle("Pinch & Zoom")
        .navigationBarTitleDisplayMode(.inline)
        .onAppear {
                isAnimating = true
        }
    } // END of Navigation View
  }
}

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM