简体   繁体   English

SwiftUI - 显示工作表后导航栏按钮不可点击

[英]SwiftUI - Navigation bar button not clickable after sheet has been presented

I have just started using SwiftUI a couple of weeks ago and i'm learning.几周前我刚刚开始使用 SwiftUI,我正在学习。 Today I ran into a into an issue.今天我遇到了一个问题。

When I present a sheet with a navigationBarItems-button and then dismiss the ModalView and return to the ContentView I find myself unable to click on the navigationBarItems-button again.当我展示一个带有 navigationBarItems 按钮的工作表,然后关闭 ModalView 并返回到 ContentView 时,我发现自己无法再次单击 navigationBarItems 按钮。

My code is as follows:我的代码如下:

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")
            }
        }
    }
}

I think this happens because the presentationMode is not inherited from the presenter view, so the presenter didn't know that the modal is already closed.我认为发生这种情况是因为presentationMode不是从演示者视图继承的,所以演示者不知道模式已经关闭。 You can fix this by adding presentationMode to presenter, in this case to ContentView.您可以通过将presentationMode添加到presenter(在本例中为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")
                }
            )
        }
    }
}

Tested on Xcode 12.5.在 Xcode 12.5 上测试。

Here is the full working example .这是完整的工作示例

This seems to be a bug in SwiftUI.这似乎是 SwiftUI 中的一个错误。 I am also still seeing this issue with Xcode 11.5 / iOS 13.5.1.我还在 Xcode 11.5 / iOS 13.5.1 中看到这个问题。 The navigationBarMode didn't make a difference. navigationBarMode 没有任何区别。

I filed an issue with Apple:我向 Apple 提出了问题:


FB7641003 - Taps on a navigationBarItem Button presenting a sheet sometimes not recognized FB7641003 - 点击显示工作表的 navigationBarItem 按钮有时无法识别

You can use the attached example project SwiftUISheet (also available via https://github.com/ralfebert/SwiftUISheet ) to reproduce the issue.您可以使用随附的示例项目SwiftUISheet (也可通过https://github.com/ralfebert/SwiftUISheet获得)来重现该问题。 It just presents a sheet from a navigation bar button.它只是显示导航栏按钮的工作表。 Run the app and tap repeatedly on the 'plus' button in the nav bar.运行应用程序并反复点击导航栏中的“加号”按钮。 When the sheet pops up, dismiss it by sliding it down.当工作表弹出时,向下滑动将其关闭。 Only some taps to the button will be handled, often a tap is ignored.只会处理对按钮的一些点击,通常会忽略点击。

Tested on Xcode 11.4 (11E146) with iOS 13.4 (17E255).使用 iOS 13.4 (17E255) 在 Xcode 11.4 (11E146) 上进行测试。

I'm still seeing this issue with Xcode 13 RC and iOS 15. Unfortunately the solutions above didn't work for me.我仍然看到 Xcode 13 RC 和 iOS 15 的这个问题。不幸的是,上面的解决方案对我不起作用。 What I ended up doing is adding a small Text view to the toolbar whose content changes depending on the value of the .showingSheet property.我最终做的是向工具栏添加一个小的文本视图,其内容根据.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")
                    }
                }
            }
        }
    }
}

I realize it's not ideal but it's the first thing that worked for me.我意识到这并不理想,但这是对我有用的第一件事。 My guess is that having the Text view's content change depending on the .showingSheet property forces SwiftUI to fully refresh the toolbar group.我的猜测是,根据.showingSheet属性更改文本视图的内容会强制 SwiftUI 完全刷新工具栏组。

This is a Bug that is related to the .large navigationBarItem.这是一个与.large navigationBarItem 相关的Bug You can set that to .inline to go around it for now:您现在可以将其设置为.inline到 go 周围:

    NavigationView {
        ,,,

        .navigationBarTitle(Text(""), displayMode: .inline)
    }

To see the bug : Drag down the button to make it work on .large mode;)要查看错误:向下拖动按钮以使其在.large模式下工作;)

So far, I can still observe the disorder of navi buttons right after dismissing its presented sheet.到目前为止,我仍然可以在关闭其呈现的表格后立即观察到导航按钮的混乱。

FYI, I am using a UINavigationController wrapper instead as workaround.仅供参考,我正在使用 UINavigationController 包装器作为解决方法。 It works well.它运作良好。

Unfortunately, I sure that the more that kind of bugs, the farther away the time of using SwiftUI widely by the ios dev guys.不幸的是,我确信这种错误越多,ios 开发人员广泛使用 SwiftUI 的时间就越远。 Because those are too basic to ignore.因为这些太基础了,不容忽视。

Very hacky but this worked for me:非常hacky,但这对我有用:

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

Very hacky but this worked for me:非常hacky,但这对我有用:

I had the same problem.我有同样的问题。 this solution worked for me.这个解决方案对我有用。

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)
                }
            )
        }
    }
}

Only @adamwjohnson5's answer worked for me.只有@adamwjohnson5 的回答对我有用。 I don't like doing it but it's the only solution that works as of Xcode 13.1 and iOS 15.0.我不喜欢这样做,但它是唯一适用于 Xcode 13.1 和 iOS 15.0 的解决方案。 Here is my code for anyone interested in seeing iOS 15.0 targeted code:对于有兴趣查看 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)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM