为啥在 SwiftUI 中点击按钮的手势甚至在它的框架之外也会被触发?

Posted

技术标签:

【中文标题】为啥在 SwiftUI 中点击按钮的手势甚至在它的框架之外也会被触发?【英文标题】:Why tap Gesture of Button get triggered even out side of it's frame in SwiftUI?为什么在 SwiftUI 中点击按钮的手势甚至在它的框架之外也会被触发? 【发布时间】:2020-12-17 02:50:03 【问题描述】:

我正在测试识别 SwiftUI 中一个简单按钮的点击手势的准确性,我注意到它甚至在框架之外也被激活了!我想确保我没有弄乱按钮的标签或其他东西,在那里我构建了 2 个不同的按钮以找到任何改进,但它们都在给定框架之外触发。我制作了一个 gif 来显示问题。

gif:

代码:

    struct ContentView: View 
    var body: some View 
        
        Spacer()

        
        Button("tap me!") 
            
            print("you just tapped Button1!")
            
        .font(Font.largeTitle.bold()).background(Color.red)
        
        
        Spacer()
        
        
        Button(action: 
            
            print("you just tapped Button2!")
            
        , label: 
            Text("tap me!").font(Font.largeTitle.bold()).background(Color.red)
        )

        Spacer()
 
    

更新:

有人说:

点击时你看到圆圈了吗? - 它是活动点击点(一种手指)的大小,如您所见,从您自己的演示中,它与红色正方形重叠 - 因此检测到手势。就是这样

我制作了另一个 gif 来表明这样的想法是完全错误的,在这个 gif 中,即使有重叠点击也没有注册!

【问题讨论】:

点击时看到圆圈了吗? - 它是活动点击点(一种手指)的大小,如您所见,从您自己的演示中,它与红色正方形重叠 - 因此检测到手势。就是这样。 @Asperi:就这样?太简单?我不这么认为!谁设置了那个圈子?我?那个圆的半径在哪里?我怎样才能更新那个圈子?顺便说一句,我可以从视频录制设置中隐藏那个圆圈,它只是为了显示点击或点击区域。 我看不出问题出在哪里。人们不会用针点击按钮。你的指尖是 1 厘米宽。 @ElTomato:为什么 o 为什么你是这个级别的东西,兄弟?问题不在于! 【参考方案1】:

我不知道为什么会发生这种情况,只是可能有一些内置功能可以在可能的情况下增加可点击区域以获得更好的用户体验?无论如何,如果您在其后面或旁边放置另一个可点击按钮,您会注意到这种情况不再发生,并且可点击区域正是您所期望的。因此,我不会担心它。但是,如果您需要将点击区域剪切到确切的帧,您可以为按钮添加一个清晰的背景,并添加一个不执行任何操作但优先于该位置的点击事件。

var body: some View 
    VStack 
        
        // Button behind button will take priority tap.
        ZStack 
            
            Button(action: 
                print("tap 2")
            , label: 
                Text("tap me!")
                    .padding()
                    .font(Font.largeTitle.bold())
                    .background(Color.green)
            )

            Button(action: 
                print("tap 1")
            , label: 
                Text("tap me!")
                    .font(Font.largeTitle.bold())
                    .background(Color.red)
            )
        

        // Clear background with "fake" tap event
        Button(action: 
            print("tap 3")
        , label: 
            Text("tap me!")
                .font(Font.largeTitle.bold())
                .background(Color.red)
        )
        .padding()
        .background(Color.black.opacity(0.001).onTapGesture 
            //print("tap 4")
        )

    

【讨论】:

@nicksarno:正如你所说,我同意你的一些内置功能,这些功能可以在可能的情况下增加可点击区域以获得更好的用户体验。如果我想解释我的想法,它将是视图周围的(对我们而言)无法访问的框架,并且比实际框架大一点!但是我如何访问这个框架或停用这个框架是我的问题。 我的回答解释了为什么这不是一个真正的问题,并展示了如何将可点击区域完全限制在框架内。 这是一个真正的问题!我不必翻转我的代码来获得代码的正常行为。 什么时候会出现问题?如果有的话,这对开发人员来说是一件好事,因为它改善了用户体验。【参考方案2】:

我认为这是扩展可点击区域的内置功能:

Color.red
    .frame(width: 30.0, height: 30.0)
    .gesture(DragGesture(minimumDistance: 0).onEnded( (value) in
        // Tap with Apple Pencil: location is exactly the frame
        // Tap with finger or an capacitance pen: the hit location is inaccurate
        print(value.startLocation)
    ))

解决方案(Bug:如果视图在 ScrollView 内,这将阻止滚动手势):

let size = CGSize(width: 200.0, height: 200.0)
Color.red
    .frame(width: size.width, height: size.height)
    .gesture(DragGesture(minimumDistance: 0).onEnded( (value) in
        print(value.startLocation)
        if value.startLocation.x >= 0 && value.startLocation.y >= 0 && value.startLocation.x <= size.width && value.startLocation.y <= size.height 
            print("inside frame")
            // action ...
         else 
            print("outside frame")
        
    ))

【讨论】:

以上是关于为啥在 SwiftUI 中点击按钮的手势甚至在它的框架之外也会被触发?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中点击手势时放大缩小按钮动画?

斯威夫特:为啥点击手势识别器不是每次都有效?

如何制作 SwiftUI 手势,在按下视图时继续运行代码

SwiftUI:ListItem 手势

使用 SwiftUI,我们在 List 中安装了一个 Button。为啥当我点击按钮显示模态然后再次关闭时模态消失?

在 SwiftUI for macOS 应用程序中获取点击手势的鼠标/指针位置