【问题标题】:SwiftUI - Navigation bar button not clickable after sheet has been presentedSwiftUI - 呈现工作表后导航栏按钮不可点击
【发布时间】:2020-02-19 01:56:02
【问题描述】:

几周前我刚刚开始使用 SwiftUI,我正在学习。今天我遇到了一个问题。

当我展示带有 navigationBarItems 按钮的工作表然后关闭 ModalView 并返回 ContentView 时,我发现自己无法再次单击 navigationBarItems 按钮。

我的代码如下:

struct ContentView: View {

    @State var showSheet = false

    var body: some View {
        NavigationView {
            VStack {
                Text("Test")
            }.sheet(isPresented: self.$showSheet) {
                ModalView()
            }.navigationBarItems(trailing:
                Button(action: {
                    self.showSheet = true
                }) {
                    Text("SecondView")
                }
            )
        }
    }
}

struct ModalView: View {

    @Environment(\.presentationMode) var presentation

    var body: some View {
        VStack {
            Button(action: {
                self.presentation.wrappedValue.dismiss()
            }) {
                Text("Dismiss")
            }
        }
    }
}

【问题讨论】:

  • Markus,你检查过我的答案吗?对你有用吗?
  • 哇!这在 WWDC 2021 的第一天仍然存在。也许下一个版本。

标签: swift xcode swiftui


【解决方案1】:

这似乎是 SwiftUI 中的一个错误。我仍然在 Xcode 11.5 / iOS 13.5.1 中看到这个问题。 navigationBarMode 没有任何区别。

我向 Apple 提出了问题:


FB7641003 - 点击导航栏项目按钮,有时无法识别显示工作表

您可以使用随附的示例项目SwiftUISheet(也可通过https://github.com/ralfebert/SwiftUISheet 获得)重现该问题。它只是显示导航栏按钮的工作表。 运行应用程序并反复点击导航栏中的“加号”按钮。当工作表弹出时,向下滑动将其关闭。只会处理对按钮的一些点击,通常会忽略点击。

在 Xcode 11.4 (11E146) 和 iOS 13.4 (17E255) 上测试。

【讨论】:

  • 这有什么更新吗?根据我的经验,如果我向下滑动以关闭视图,我可以点击按钮并再次将其恢复。但是,如果我点击工作表上的“完成”按钮关闭,则另一个导航项 + 不起作用。
  • @LukeIrvin 你试过我提供的解决方案了吗?
  • 在 FB 上获得更新以在 iOS 13.5 Beta 4 上重新测试(我目前没有测试版设备,只是想让您了解最新情况)
  • 我正在经历同样的事情,仍然在 13.5.1 和 Xcode 11.5 (11E608c) 上。我似乎遇到了@LukeIrvin 的相反问题,如果我点击我的“关闭”按钮,下次显示模式会更可靠,但向下滑动会使情况变得更糟。不过,我偶尔也会遇到问题。
  • 我与一位 Apple 工程师进行了一次 WWDC 实验室会议,专注于这个错误。工程师似乎口头承认这似乎是一个错误,并且他在他的设备上注意到了同样的事情。我的反馈(提到 FB7641003)没有回复或跟进。
【解决方案2】:

我认为这是因为presentationMode 不是从演示者视图继承的,所以演示者不知道模式已经关闭。您可以通过将 presentationMode 添加到演示者(在本例中为 ContentView)来解决此问题。

struct ContentView: View {

    @Environment(\.presentationMode) var presentation
    @State var showSheet = false

    var body: some View {
        NavigationView {
            VStack {
                Text("Test")
            }.sheet(isPresented: self.$showSheet) {
                ModalView()
            }.navigationBarItems(trailing:
                Button(action: {
                    self.showSheet = true
                }) {
                    Text("SecondView")
                }
            )
        }
    }
}

在 Xcode 12.5 上测试。

这是完整的工作 example.

【讨论】:

  • 也适用于我 - 我不认为这是 Apple 的预期行为,但在他们修复它之前这是一个很好的解决方法。这应该是公认的答案。
  • 非常好。初次按下后,我也无法单击加号按钮。这个解决方案对我有用。谢谢
  • 只有我这个方法不适用吗?有些水龙头只是没有注册。我仍然确信这是一个 SwiftUI 错误,并且我让一位 Apple 工程师在 WWDC20 实验室会议上口头同意。我迫切需要一种解决方法。
  • 我现在意识到我们正在谈论两个不同的错误。使用该确切代码,我仍然遇到与@Ralf Ebert 相同的问题 - 很多时候,“SecondView”上的点击未注册。我相信这是一个基本的 SwiftUI 错误。对于这个特定的代码,注释掉presentationMode行对我来说没有任何改变。在这两种情况下,它都会显示带有或不带有该行的工作表,并且按钮始终无响应。
  • 拯救了我的一天。谢谢。 Xcode 12.5 中仍然存在问题
【解决方案3】:

到目前为止,我仍然可以在关闭其呈现的表格后立即观察到导航按钮的混乱。

仅供参考,我使用 UINavigationController 包装器作为解决方法。它运行良好。

不幸的是,我确信这种错误越多,iOS 开发人员广泛使用 SwiftUI 的时间就越远。因为这些太基础了,不容忽视。

【讨论】:

  • 您是否有链接到如何使用 UINavigationController 包装器作为解决方法?我想试试。
【解决方案4】:

非常老套,但这对我有用:

Button(action: {
    self.showSheet = true
}) {
    Text("SecondView")
    .frame(height: 96, alignment: .trailing)
}

【讨论】:

  • 这是唯一对我有用的解决方案。在 Xcode 13.1 和 iOS 15.0 上测试。
【解决方案5】:

非常老套,但这对我有用:

我遇到了同样的问题。这个解决方案对我有用。

struct ContentView: View {

    @State var showSheet = false

    var body: some View {
        NavigationView {
            VStack {
                Text("Test")
            }.sheet(isPresented: self.$showSheet) {
                ModalView()
            }.navigationBarItems(trailing:
                Button(action: {
                    self.showSheet = true
                }) {
                    Text("SecondView")
                        // this is a workaround
                        .frame(height: 96, alignment: .trailing)
                }
            )
        }
    }
}

【讨论】:

    【解决方案6】:

    我仍然在 Xcode 13 RC 和 iOS 15 中看到这个问题。不幸的是,上面的解决方案对我不起作用。我最终做的是向工具栏添加一个小的 Text 视图,其内容根据.showingSheet 属性的值而变化。

    struct ContentView: View {
        @State private var showingSheet = false
    
        var body: some View {
            NavigationView {
                VStack {
                    Text("Content view")
                    Text("Swift UI")
                }
                .sheet(isPresented: $showingSheet) {
                    Text("This is a sheet")
                }
                .navigationTitle("Example")
                .toolbar {
                    ToolbarItemGroup(placement: .navigationBarTrailing) {
                        // Text view workaround for SwiftUI bug
                        // Keep toolbar items tappable after dismissing sheet
                        Text(showingSheet ? " " : "").hidden()
                        Button(action: {
                            self.showingSheet = true
                        }) {
                            Label("Show Sheet", systemImage: "plus.square")
                        }
                    }
                }
            }
        }
    }
    

    我意识到这并不理想,但这是对我有用的第一件事。我的猜测是,根据.showingSheet 属性更改 Text 视图的内容会强制 SwiftUI 完全刷新工具栏组。

    【讨论】:

      【解决方案7】:

      只有@adamwjohnson5 的回答对我有用。我不喜欢这样做,但它是唯一适用于 Xcode 13.1 和 iOS 15.0 的解决方案。这是我的代码,供有兴趣查看 iOS 15.0 目标代码的任何人使用:

      var body: some View {
          NavigationView {
              mainContentView
                  .navigationTitle(viewModel.navigationTitle)
                  .toolbar {
                      ToolbarItem(placement: .navigationBarTrailing) {
                          PlusButton {
                              viewModel.showAddDialog.toggle()
                          }
                          .frame(height: 96, alignment: .trailing) // Workaroud, credit: https://stackoverflow.com/a/62209223/5421557
                          .confirmationDialog("CatalogView.Add.DialogTitle", isPresented: $viewModel.showAddDialog, titleVisibility: .visible) {
                              Button("Program") {
                                  viewModel.navigateToAddProgramView.toggle()
                              }
                              
                              Button("Exercise") {
                                  viewModel.navigateToAddExerciseView.toggle()
                              }
                          }
                      }
                  }
                  .sheet(isPresented: $viewModel.navigateToAddProgramView, onDismiss: nil) {
                      Text("Add Program View")
                  }
                  .sheet(isPresented: $viewModel.navigateToAddExerciseView, onDismiss: nil) {
                      AddEditExerciseView(viewModel: AddEditExerciseViewModel())
                  }
          }
          .navigationViewStyle(.stack)
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-21
        • 2015-09-15
        • 2021-04-26
        • 1970-01-01
        相关资源
        最近更新 更多