SwiftUI中ScrollView内按钮的上下文菜单作用于整个Section问题
问题原因
问题出在SwiftUI的List行默认自带长按手势,当你把整个水平ScrollView放在Section的单行内时,行的长按手势优先级高于按钮的上下文菜单手势,导致长按整个Section行区域都会触发上下文菜单(视觉上像是作用于整个Section)。再加上你设置了listRowInsets(EdgeInsets())和listRowBackground(Color.clear),让行的范围与内部ScrollView完全重合,进一步放大了这个冲突。
解决方案
要让上下文菜单仅对按钮生效,只需做两个关键调整:
- 让按钮的长按手势优先:给按钮添加
.highPriorityGesture(LongPressGesture()),确保按钮的长按事件被优先识别,不会被List行的手势拦截。 - 明确按钮的交互区域:给按钮的内部内容设置
.contentShape(Rectangle()),限定长按触发范围严格对应按钮本身。
修改后的"创建"按钮代码
Button(action: { showingTemplateAddSheet = true }) { VStack { Image(systemName: "plus") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 30, height: 30) .padding() .background(colorScheme == .dark ? Color.gray.opacity(0.2) : Color.white) .cornerRadius(10) Text("Создать") .foregroundColor(.primary) .font(.footnote) .multilineTextAlignment(.center) .padding(.top, 5) .frame(width: 80) } .frame(width: 80, height: 100) .contentShape(Rectangle()) // 明确按钮的交互边界 } .sheet(isPresented: $showingTemplateAddSheet) { NewTemplateView(templateItem: nil, shouldRefreshParentView: $shouldRefreshParentView, defaultType: filterTypeView) .environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil) } .contextMenu { Button("HELLO"){ } } .highPriorityGesture(LongPressGesture()) // 提升按钮长按手势优先级
循环生成的模板按钮同理修改
ForEach(filteredTemplates) { item in Button(action: { selectedTemplateItem = item }) { VStack { Image(systemName: "\(item.iconName)") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 30, height: 30) .padding() .background(colorScheme == .dark ? Color.gray.opacity(0.2) : Color.white) .cornerRadius(10) Text(item.name) .foregroundColor(.primary) .font(.footnote) .multilineTextAlignment(.center) .padding(.top, 5) .frame(width: 80) } .frame(width: 80, height: 100) .contentShape(Rectangle()) } .contextMenu { Button("编辑模板") { // 编辑逻辑 } Button("删除模板") { // 删除逻辑 } } .highPriorityGesture(LongPressGesture()) }
可选补充:禁用List行的长按手势
如果你想彻底避免行手势的干扰,也可以给ScrollView所在的Section行添加空的长按处理,吃掉行的长按事件:
ScrollView(.horizontal, showsIndicators: false) { // ... 内部内容 ... } .listRowBackground(Color.clear) .listRowInsets(EdgeInsets()) .onLongPressGesture {} // 拦截行的长按手势
调整完成后,长按按钮只会触发自身的上下文菜单,不会影响整个Section区域。
内容的提问来源于stack exchange,提问作者Haji Lazgiyev
相关产品推荐
相关产品推荐

