使用 clipped() 裁切视图后,虽然视图的显示区域变小了,但是点击区域却还是被裁前的区域。因此如果有的视图需要裁剪后要接收触摸事件,需要做一下处理。
举例说明
假设我们把一个300x300矩形的 frame 设置成100x100:
swift
Rectangle()
.fill(.orange.gradient)
.frame(width: 300, height: 300)
// Set view to 100×100 → renders out of bounds
.frame(width: 100, height: 100)
.border(.blue)
从图上可以看出有边框的部分是实际UI渲染的面积,外面的部分在 frame 外的。如果我们把这个视图裁切后,把一个按钮放置在蓝色边框外,按钮其实会因为被矩形遮挡而接收不了点击事件。
swift
struct ContentView: View {
@State var buttonTapCount = 0
@State var rectTapCount = 0
var body: some View {
VStack {
Text("buttonTapCount:\(buttonTapCount)")
Text("rectTapCount:\(rectTapCount)")
Button("点击无效") {
buttonTapCount += 1
}
.buttonStyle(.borderedProminent)
Rectangle()
.fill(.orange.gradient)
.frame(width: 300, height: 300)
.frame(width: 100, height: 100)
.clipped()
.onTapGesture {
rectTapCount += 1
}
}
}
}
效果如下,可以看到点击按钮的事件没有被正确的接受,还是算到了矩形上:
修复:使用 .contentShape()
使用 contentShape
方法可以设置 view 的点击响应区域。因此在裁剪后如果加上 .contentShape()
后就可以得到正确的点击区域。
swift
Rectangle()
.fill(.orange.gradient)
.frame(width: 300, height: 300)
.frame(width: 100, height: 100)
.clipped()
.contentShape(Rectangle())
在设置完 contentShape 效果就和我预期的一样了: