我正在努力解决一个SwiftUI问题:
在一个非常抽象的方式,这是我的应用程序的代码看起来像(不是实际的代码,只是这里讨论的事情):
struct SwiftUIView: View {
@State private var toggle: Bool = true
var body: some View {
VStack {
Spacer()
if toggle {
Text("on")
} else {
Text("off")
}
Spacer()
Rectangle()
.frame(height: 200)
.onTapGesture { toggle.toggle() }
Spacer()
Menu("Actions") {
Button("Duplicate", action: { toggle.toggle() })
Button("Rename", action: { toggle.toggle() })
Button("Delete", action: { toggle.toggle() })
}
Spacer()
}
}
}
所以这里的精髓是什么?
- 背景中有一个元素(矩形),它对用户的点击输入做出React
- 有一个菜单,其中包含的项目,也进行一些行动时,点击
现在,我面临着以下问题:
当点击“操作”打开菜单时,菜单会打开-到目前为止一切顺利。然而,当我现在决定不想触发菜单中包含的任何操作,并点击背景上的某个地方来关闭它时,可能会发生我点击背景中的矩形。如果我这样做,在矩形上的点击直接触发onTapGesture中定义的操作。
然而,理想的行为是,当菜单打开时,我可以点击菜单外的任何位置来关闭它,而不会**触发任何其他元素。
你知道我该怎么做吗?谢谢你,谢谢
(Let我在评论中知道是否需要进一步澄清。
6条答案
按热度按时间eqfvzcg81#
您可以实现一个
.overlay
,它是可扩展的,当您点击菜单时会出现。让它覆盖整个屏幕,它会被菜单忽略。当点击菜单图标时,您可以将属性设置为true。当点击覆盖或菜单项时,将其设置回false。你可以把它放在你的根视图中,并使用带有@Environment的视图模型来从任何地方访问它。
唯一的缺点是,你需要在每个菜单按钮中放置
isMenuOpen = false
。苹果正在使用意想不到的行为本身,一个.ex在天气应用程序。但是,我仍然认为这是一个bug,并提交了一份报告。(FB10033181)
sc4hvdpw2#
这并不令人惊讶,但您可以使用@State var手动跟踪菜单的状态,并在菜单的.onTap中将其设置为true。
然后,您可以根据需要将.disabled(inMenu)应用于背景元素。但是你需要确保菜单的所有退出都正确地将变量设置回false。所以这意味着a)任何菜单项的操作都应该将其设置为false,b)在菜单外点击,包括。在技术上被“禁用”的区域上,也需要将其切换回false。
根据视图层次结构,有很多方法可以实现这一点。最激进的方法(就不错过菜单退出而言)可能是有条件地覆盖一个清晰的阻塞视图,并使用.onTap将inMenu设置为false。然而,这可能具有可访问性的缺点。当然,最理想的情况是,只有一种方法可以直接绑定到菜单的presentationMode,或者可以在菜单上配置对周围点击的处理。与此同时,上面的方法对我来说很有效。
wvyml7n53#
我想我有一个解决方案,但它是一个黑客. * 和 * 它不会与SwiftUI“应用程序”生命周期工作。
在你的
SceneDelegate
中,不要创建一个UIWindow
,而是使用这个HackedUIWindow
子类:子类监视添加/删除的子视图,查找上下文菜单使用的
_UIContextMenuContainerView
类型。当它看到一个被添加,它抓住窗口的根视图和禁用用户交互;当上下文菜单被移除时,它重新启用用户交互。这在我的测试工作,但YMMV。对
"_UIContextMenuContainerView"
字符串进行模糊处理也是明智的,这样App Review就不会注意到您引用了私有类。33qvvth14#
在我的情况下,警报被阻止显示在类似的情况下,与菜单以及日期选择器冲突。我的解决方法是使用DispatchQueue的轻微延迟。
唯一真实的解决方案将发生在苹果修复/完善SwiftUI关于菜单(和日期选择器)的行为。
sqxo8psd5#
我可以通过不使用
.onTapGesture
并将List
项目 Package 在Button
中来解决这个问题。这可以通过转换为视图修改器来进一步改进。dluptydi6#
您可以通过使用
Form
或List
而不是“plain view”来获得所需的行为。当菜单在屏幕上时,所有按钮将默认禁用,但它们需要是按钮,每个单元格只有一个,它不会与tapGesture
一起工作,因为你实际上正在做的是点击单元格,SwiftUI正在为你禁用TableView点击。实现这一目标的关键要素是:
Form
或List
Button
。* 在您的示例中,您使用Rectangle
和tapGesture
。*我修改了你提供的代码,如果你打开菜单,你不能点击按钮: