ios - SwiftUI - 在 iPadOS 和 Catalyst 上使用 onTapGesture 和鼠标/触控板出现意外行为

标签 ios swift swiftui mac-catalyst ipados

我在我的应用程序中有一个显示矩形卡片列表的布局 - 每个卡片都应该可以点击(一次)以显示一组操作按钮和更多信息等。
我已经使用 .onTapGesture() 实现了这个我也放了.contentShape(Rectangle()强制执行可点击区域。然而,虽然我的实现适用于触摸屏界面,但当我将它与 iPadOS 鼠标支持一起使用时,以及在 Catalyst 上,我看到了一些非常意外的行为。
我在下面制作了一个最小的可重现示例,您可以复制该示例以重现问题。
使用鼠标/触控板输入时的问题所在:

  • 并非每次单击鼠标都记录为点击手势。除了少数情况外,这几乎是任意发生的:
  • 它似乎只在非常特定的区域单击,或者在同一位置多次单击时单击。
  • 似乎在很多情况下,只记录每隔一次点击。所以我双击只得到一个点击手势。
  • 在此示例代码中并不明显,但在我的主应用程序中,可点击区域似乎是任意的 - 您通常可以单击文本附近或与其对齐以记录点击手势,但并非总是如此。

  • 如果您正在运行示例代码,您应该能够通过反复移动鼠标并尝试单击来查看问题。除非您在同一位置多次单击,否则它不起作用。
    什么按预期工作 :
  • 所有输入都使用触摸而不是鼠标;无论您在哪里点击它都会记录点击手势。
  • 作为 native Mac 目标运行时的鼠标输入。上述问题仅针对在 iPadOS 和 Mac Catalyst 下运行示例时的鼠标/触控板。

  • 我用来重现这个问题的代码(每次记录点击手势时都有一个计数器来计数):
    struct WidgetCompactTaskItemView: View {
        
        let title: String
        let description: String
        
        var body: some View {
            HStack {
                Rectangle()
                    .fill(Color.purple)
                    .frame(maxWidth: 14, maxHeight: .infinity)
                VStack(alignment: .leading) {
                    Text(title).font(.system(size: 14, weight: .bold, design: .rounded))
                    Text(description).font(.system(.footnote, design: .rounded))
                        .frame(maxHeight: .infinity)
                        .fixedSize(horizontal: false, vertical: true)
                        .lineLimit(1)
                        .padding(.vertical, 0.1)
                    Spacer()
                }
                .padding(.horizontal, 6)
                .padding(.top, 12)
            }
            .frame(maxWidth: .infinity, maxHeight: 100, alignment: .leading)
            .background(Color.black)
            .cornerRadius(16)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.green, lineWidth: 0.5)
                )
        }
    }
    
    struct ContentView: View {
        @State var tapCounter = 0
        var body: some View {
            VStack {
                Text("Button tapped \(tapCounter) times.")
                WidgetCompactTaskItemView(title: "Example", description: "Description")
                    .contentShape(Rectangle())
                    .onTapGesture(count: 1) {
                        tapCounter += 1
                    }
                Spacer()
            }
         }
    }
    
    我尝试了几件事,包括移动修饰符,设置 eoFillcontentShape上为真修饰符(它没有解决问题,只是做了不同的意外行为)。
    任何帮助找到 按预期工作并始终如一地工作的解决方案 鼠标或触摸将不胜感激。我不确定我是否做错了什么或者这里是否有错误,所以请尝试使用代码自己重新创建这个示例,看看是否可以重现问题。

    最佳答案

    所以我意识到有一个更好的解决方案可以绕过.onTapGesture 的所有奇怪之处。我用鼠标输入。它将整个 View 封装在 Button 中反而。
    我把它变成了一个类似于 onTapGesture 的修饰符,这样它就更实用了。

    
    import Foundation
    import SwiftUI
    
    public struct UltraPlainButtonStyle: ButtonStyle {
        public func makeBody(configuration: Self.Configuration) -> some View {
            configuration.label
        }
    }
    
    struct Tappable: ViewModifier {
        let action: () -> ()
        func body(content: Content) -> some View {
            Button(action: self.action) {
                content
            }
            .buttonStyle(UltraPlainButtonStyle())
        }
    }
    
    extension View {
        func tappable(do action: @escaping () -> ()) -> some View {
            self.modifier(Tappable(action: action))
        }
    }
    
    经历这个:
    我首先有一个按钮样式,它只是按原样返回标签。这是必要的,因为默认 PlainButtonStyle()单击时仍然具有可见效果。
    然后我创建了一个修饰符来封装 Button 中给出的内容。使用此按钮样式,然后将其添加为 View 的扩展名.
    用法示例
    WidgetCompactTaskItemView(title: "Example", description: "Description")
                    .tappable {
                        tapCounter += 1
                    }
    
    这已经解决了我使用鼠标在可点击区域上遇到的所有问题。

    关于ios - SwiftUI - 在 iPadOS 和 Catalyst 上使用 onTapGesture 和鼠标/触控板出现意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65047746/

    相关文章:

    ios - iOS SwiftUI中ForEach内部的if语句

    swift - 列表涵盖 SwiftUI 中的自定义 View

    ios - 在 SwiftUI 中切换 View 后 Firebase 图像为空

    ios - 在 iOS 8 中永远在后台运行应用程序

    ios - 这个 Today Extension (iOS8) 可能吗?

    swift - 沙箱发送 AppleEvent 失败

    ios - 使用电话号码身份验证的 token 不匹配 - iOS

    iphone - 如何计算字典中的重复对象?

    iphone - 如何动态更改 UIButton 的位置

    swift - macOS - UserDefaults 在 Swift 和 Terminal 中是不同的