响应区域的扩大
🌰 现在有个Text,需要给它添加一个点击事件,代码如下:
struct PlaygroundView: View {
var body: some View {
VStack {
Text("Tap me")
.background(.yellow)
.onTapGesture {
print("what?")
}
Spacer()
}
.padding(.top, 20)
}
}
效果如下:
可以没问题,但由于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当前背景,这样就能实现点击区域的扩大了:
加点透明度可以看到点击区域实际为:
可能会有人觉得疑惑,为什么设置个这么小的透明度,直接设置为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
}
}
}
}
}
}
}
实现效果:
PS:额外添加了一些动画效果,并且在上下各自添加一个按钮,可以看到当HUD存在时是点击不到这些按钮的。
再看看透明度设置为0或者使用clear会发生什么:
可以看到,HUD的区域即便是全屏覆盖的,但点击事件还是穿透到下一层了,上下按钮都能被点击。所以全透明的Color是不会有交互性的!
总结
使用非clear的Color,只要透明度设置在0.000000001 ~ 0.001这个区间内,就能实现“完全透明”并且具有交互性,利用该特性可以自定义一块透明的可点击区域。