【iOS】SwiftUI 使用Color巧妙实现「响应区域的扩大」及「可拦截点击事件的透明背景」

3,040 阅读2分钟

响应区域的扩大

🌰 现在有个Text,需要给它添加一个点击事件,代码如下:

struct PlaygroundView: View {
    var body: some View {
        VStack {
            Text("Tap me")
                .background(.yellow)
                .onTapGesture {
                    print("what?")
                }
                
            Spacer()
        }
        .padding(.top, 20)
    }
}

效果如下:

jp_gif_file.GIF

可以没问题,但由于Text太小,好难点到,那么如何不更换Text及其位置的前提下,扩大其点击区域?

要实现这个需求有很多种方法,例如设置Text的frame,但是这样的话还得修改offset,另外如果是复杂页面的话,很有可能会影响到其他子View,总的来说就是比较麻烦。

这里介绍一种超简单的方案:使用Color

Talk is cheap. Show me the code:

struct PlaygroundView: View {
    var body: some View {
        VStack {
            Text("Tap me")
                .background(.yellow)
                .background {
                    Color.red.opacity(0.000000001)
                        .frame(width: 150, height: 150)
                }
                .onTapGesture {
                    print("what?")
                }
                
            Spacer()
        }
        .padding(.top, 20)
    }
}

这里是给Text添加了一个宽高为150、接近完全透明的Color当前背景,这样就能实现点击区域的扩大了:

jp_gif_file 3.GIF

加点透明度可以看到点击区域实际为:

51687873540_.pic.jpg

可能会有人觉得疑惑,为什么设置个这么小的透明度,直接设置为0或者直接使用clear不就好了么?

这是因为如果设置为0或者使用clear,系统定义该区域为隐藏,是无法交互的(手势无法响应)

但经过实测,只要透明度设置在0.000000001 ~ 0.001这个区间内,在屏幕上是无法看到的(大于0.001就会依稀看到),但实则存在,并且具有交互性的

利用这个特性,完全不用挪动Text,就能实现其点击区域的扩大了!

可拦截点击事件的透明背景

这个特性除了可以扩大点击区域,还可以给透明背景的HUD,实现点击背景自动关闭的效果。

示例代码如下:

struct PlaygroundView: View {
    @State var isShowPrompt = false
    
    var body: some View {
        VStack {
            Button {
                isShowPrompt.toggle()
            } label: {
                Text("Hello, World!")

            }
            .opacity(isShowPrompt ? 0 : 1)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .overlay {
                if isShowPrompt {
                    PromptView()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background {
                            Color.red.opacity(0.000000001)
                                .onTapGesture {
                                    isShowPrompt = false
                                }
                        }
                }
            }
        }
    }
}

实现效果:

jp_gif_file 4.GIF

PS:额外添加了一些动画效果,并且在上下各自添加一个按钮,可以看到当HUD存在时是点击不到这些按钮的。

再看看透明度设置为0或者使用clear会发生什么:

jp_gif_file 5.GIF

可以看到,HUD的区域即便是全屏覆盖的,但点击事件还是穿透到下一层了,上下按钮都能被点击。所以全透明的Color是不会有交互性的!

总结

使用非clearColor,只要透明度设置在0.000000001 ~ 0.001这个区间内,就能实现“完全透明”并且具有交互性,利用该特性可以自定义一块透明的可点击区域。