SwiftUI中GridRow的onTapGesture在空白区域无法触发的问题咨询
SwiftUI GridRow 点击空白区域不触发onTapGesture的解决办法
问题描述
使用SwiftUI的Grid组件制作表格时,点击GridRow内无文本或图片的空白区域时,onTapGesture不会触发,仅点击图片或文本时可正常触发。相关代码如下:
Grid (alignment: .leading, horizontalSpacing: 0, verticalSpacing: 5) { GridRow { Color.clear.gridCellUnsizedAxes([.horizontal, .vertical]) Text("Header 1") .gridColumnAlignment(.leading) .frame(width: 400, height: 60, alignment: .leading) Text("Header 2") .frame(width: 400, height: 60, alignment: .leading) } .background(Color.headerTableBackground) ForEach(personas, id: \.self) { persona in GridRow { Image(selection?.id == persona.id ? "RadioButtonOn" : "RadioButtonOff") .renderingMode(.original) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 30, height: 30) .gridCellUnsizedAxes(.horizontal) .frame(width: 40, alignment: .leading) Text(persona.name) .font(Font.helveticaNow(subtype: .Regular, size: 16)) .gridColumnAlignment(.leading) .frame(width: 400, alignment: .leading) Text(persona.surname) .font(Font.helveticaNow(subtype: .Regular, size: 16)) .frame(width: 400, alignment: .leading) } .onTapGesture { selection = persona } Divider().gridCellUnsizedAxes(.horizontal) } }
解决办法
问题根源是GridRow默认仅在包含文本、图片等可交互视图的区域响应点击,空白区域没有可触发点击事件的载体。可以通过以下两种方式解决:
方式一:给GridRow添加透明背景
给GridRow添加一个覆盖整个行范围的透明背景,让空白区域也成为可点击目标:
ForEach(personas, id: \.self) { persona in GridRow { // 原有内容保持不变 Image(selection?.id == persona.id ? "RadioButtonOn" : "RadioButtonOff") .renderingMode(.original) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 30, height: 30) .gridCellUnsizedAxes(.horizontal) .frame(width: 40, alignment: .leading) Text(persona.name) .font(Font.helveticaNow(subtype: .Regular, size: 16)) .gridColumnAlignment(.leading) .frame(width: 400, alignment: .leading) Text(persona.surname) .font(Font.helveticaNow(subtype: .Regular, size: 16)) .frame(width: 400, alignment: .leading) } .background(Color.clear) // 透明背景覆盖整个行,接收点击事件 .onTapGesture { selection = persona } Divider().gridCellUnsizedAxes(.horizontal) }
方式二:设置contentShape指定点击区域
如果添加背景后仍有问题,可通过contentShape将整个GridRow的矩形范围设为可点击区域:
ForEach(personas, id: \.self) { persona in GridRow { // 原有内容保持不变 Image(selection?.id == persona.id ? "RadioButtonOn" : "RadioButtonOff") .renderingMode(.original) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 30, height: 30) .gridCellUnsizedAxes(.horizontal) .frame(width: 40, alignment: .leading) Text(persona.name) .font(Font.helveticaNow(subtype: .Regular, size: 16)) .gridColumnAlignment(.leading) .frame(width: 400, alignment: .leading) Text(persona.surname) .font(Font.helveticaNow(subtype: .Regular, size: 16)) .frame(width: 400, alignment: .leading) } .contentShape(Rectangle()) // 把整个行的矩形范围设为点击识别区域 .onTapGesture { selection = persona } Divider().gridCellUnsizedAxes(.horizontal) }
两种方式的核心都是让整个GridRow的区域都具备点击响应能力,确保点击行内任意位置都会触发onTapGesture。
内容的提问来源于stack exchange,提问作者xarly
相关产品推荐
相关产品推荐

