SwiftUI:带有onTapGesture的列表单元格内的菜单触发手势
Posted
技术标签:
【中文标题】SwiftUI:带有onTapGesture的列表单元格内的菜单触发手势【英文标题】:SwiftUI: Menu inside list cell with onTapGesture triggers gesture 【发布时间】:2020-12-29 13:06:49 【问题描述】:我在 ios14.3 (Xcode12.3) 上有一个 SwiftUI List
,在它的单元格内,我希望在用户点击按钮时弹出一个 Menu
。此外,这些单元格有一个onTapGesture
,问题是按下菜单按钮时也会触发此手势。
示例:
List
HStack
Text("Cell content")
Spacer()
// Triggers also onTapGesture of cell
Menu(content:
Button(action: )
Text("Menu Item 1")
Image(systemName: "command")
Button(action: )
Text("Menu Item 2")
Image(systemName: "option")
Button(action: )
Text("Menu Item 3")
Image(systemName: "shift")
)
Image(systemName: "ellipsis")
.imageScale(.large)
.padding()
.background(Color(.systemBackground))
.onTapGesture
print("Cell tapped")
如果您点击省略号图像,菜单会打开,但"Cell tapped"
也会打印到控制台。这对我来说是个问题,因为在我的真实示例中,我在点击手势中折叠单元格,当然我不希望在用户按下菜单按钮时发生这种情况。
我发现,当我长按按钮时,手势不会被触发。但在我看来,这不是可接受的用户体验,我花了一段时间才自己找出来。
我还注意到,当我将Menu
替换为常规Button
时,按下时不会触发单元格手势(仅使用BorderlessButtonStyle
或PlainButtonStyle
,否则他根本不活动)。但我不知道如何从它的操作中打开菜单。
List
HStack
Text("Cell content")
Spacer()
// Does not trigger cells onTapGesture, but how to open Menu from action?
Button(action: print("Button tapped") )
Image(systemName: "ellipsis")
.imageScale(.large)
.padding()
.buttonStyle(BorderlessButtonStyle())
.background(Color(.systemBackground))
.onTapGesture
print("Cell tapped")
【问题讨论】:
是 iOS 还是 macOS 项目? 抱歉,它在 iOS14.3 和 Xcode 12.3 上 我现在也在 macOS 上对其进行了测试,打开菜单时不会触发单元格手势。尽管 Mac 上的菜单看起来非常不同(实际上是 DropDown),但我希望两个平台上的行为相同。所以我刚刚向 Apple 报告了一个错误。 【参考方案1】:或者,您可以覆盖菜单onTapGesture
:
struct ContentView: View
var body: some View
List
HStack
Text("Cell content")
Spacer()
Menu(content:
Button(action: )
Text("Menu Item 1")
Image(systemName: "command")
Button(action: )
Text("Menu Item 2")
Image(systemName: "option")
Button(action: )
Text("Menu Item 3")
Image(systemName: "shift")
)
Image(systemName: "ellipsis")
.imageScale(.large)
.padding()
.onTapGesture // override here
.contentShape(Rectangle())
.onTapGesture
print("Cell tapped")
此外,无需使用.background(Color(.systemBackground))
来点击垫片。这不是很灵活 - 如果您想更改背景颜色怎么办?
您可以改用contentShape
:
.contentShape(Rectangle())
【讨论】:
谢谢,虽然我认为@Asperi 的答案更优雅一些,而且可能更适合未来证明,但我会将其标记为已接受的答案。事实上,在我的真实示例中,单元格要复杂得多,并且菜单按钮不是右侧的最后一个子视图。主要问题是,我在我的应用程序的不同位置重用了这个单元格,并且希望根据使用的位置有不同的 onTapGestures,所以我将在单元格主体之外应用那个手势。在这种情况下,您的解决方案要好得多。 除此之外,感谢使用 contentShape 而不是背景的提示,以使垫片可点击。不知道,我还是 SwftUI 的新手,正在使用它开发我的第一个更大的应用程序。【参考方案2】:我不确定这是一个错误还是预期的行为,但我建议不要与之抗争,而是避免这种重叠(因为即使今天取得了成功,它也可能停止在不同的系统/更新上工作)。
这是可能的解决方案(使用 Xcode 12.1 / iOS 14.1 测试)
List
HStack
// row content area
HStack
Text("Cell content")
Spacer()
.background(Color(.systemBackground)) // for tap on spacer area
.onTapGesture
print("Cell tapped")
// menu area
Menu(content:
Button(action: )
Text("Menu Item 1")
Image(systemName: "command")
Button(action: )
Text("Menu Item 2")
Image(systemName: "option")
Button(action: )
Text("Menu Item 3")
Image(systemName: "shift")
)
Image(systemName: "ellipsis")
.imageScale(.large)
.padding()
【讨论】:
谢谢,这当然也解决了问题,也许是更优雅和面向未来的解决方案,但我接受了@pawello2222 的回答。原因见我对他的回答的评论。以上是关于SwiftUI:带有onTapGesture的列表单元格内的菜单触发手势的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:将链接与 onTapGesture 一起使用
SwiftUI 使用 onTapGesture 和 onLongPressGesture 处理按钮/视图以及释放操作