SwiftUI:菜单打开时如何忽略背景上的点击?

Mal*_*ito 26 menu ios swift swiftui

我目前正在努力解决 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()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

那么这里的本质是什么?

  • 背景中有一个元素(矩形)对用户的点击输入做出反应
  • 有一个菜单,其中包含点击时也会执行某些操作的项目

现在,我面临以下问题:

当通过点击“操作”打开菜单时,菜单将打开 - 到目前为止一切顺利。但是,当我现在决定不想触发菜单中包含的任何操作并点击背景上的某个位置将其关闭时,我可能会点击背景中的矩形。如果这样做,点击矩形将直接触发 onTapGesture 中定义的操作。

但是,所需的行为是当菜单打开时,我可以点击菜单外的任何位置将其关闭,而不会触发任何其他元素。

知道我该如何实现这一目标吗?谢谢!

(如果需要进一步说明,请在评论中告诉我。)

wil*_*ard 13

您可以实施一个.overlay可点击的按钮,并在点击菜单时出现。让它覆盖整个屏幕,它会被菜单忽略。点击菜单图标时,您可以将属性设置为 true。当点击覆盖层或菜单项时,将其设置回 false。

您可以将其放置在根视图中,并使用带有 @Environment 的视图模型从任何地方访问它。

唯一的缺点是,你需要放置isMenuOpen = false在每个菜单按钮中。

苹果正在使用意外行为本身,即 Wether 应用程序中的 a.ex。不过,我仍然认为这是一个错误并提交了报告。(FB10033181)

在此输入图像描述

@State var isMenuOpen: Bool = false

var body: some View {
    NavigationView{
        NavigationLink{
            ChildView()
        } label: {
            Text("Some NavigationLink")
                .padding()
        }
        .toolbar{
            ToolbarItem(placement: .navigationBarTrailing){
                Menu{
                    Button{
                        isMenuOpen = false
                    } label: {
                        Text("Some Action")
                    }
                } label: {
                    Image(systemName: "ellipsis.circle")
                }
                .onTapGesture {
                    isMenuOpen = true
                }
            }
        }
    }
    .overlay{
        if isMenuOpen {
            Color.white.opacity(0.001)
            .ignoresSafeArea()
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .onTapGesture {
                isMenuOpen = false
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 现在已经是 2023 年 5 月了,我们仍然必须使用它。就我而言,同一个“View”上有 2 个菜单和 3 个按钮,这非常丑陋! (2认同)