我找到了一种更适合SwiftUI和iOS的方法来解决在SwiftUI和iOS中导航栏(工具栏)消失的问题。
我使用工具栏来执行非常重要的命令 - 这是macOS中应用程序菜单的替代品。因此,没有工具栏会破坏我的iOS应用程序。这绝对不应该发生。然而,各种情况导致工具栏消失(例如当我关闭弹出视图或在主视图中滚动时)。为此,我似乎找到了一个可靠的解决方案。
首先是生成工具栏的模板代码 - 这是生成我的应用程序基本内容视图的象征性代码。
struct ContentView: View {
var body: some View {
let theView =
NavigationStack(root: {self.generateContentView()})
return theView
}
func generateContentView() -> some View {
let theView =
Text("This is my content view")
.toolbar {self.generateToolBar()}
}
@ToolbarContentBuilder
func generateToolBar() -> some ToolbarContent {
ToolbarItem(placement: .navigationBarTrailing) {
Text("This is a toolbar item")
}
}
}
我的解决方案是,如果我无法阻止系统做出决定不显示工具栏,我可以尝试通过将一个状态变量navigationBarIsHidden设置为false来取消隐藏。
以下是更新后的代码,在收到"renewToolbar"通知时将状态变量navigationBarIsHidden设置为false。请注意,ContentView中的修饰符.navigationBarHidden(self.navigationBarIsHidden)以及通过Task()延迟将navigationBarIsHidden更改为false。
struct ContentView: View {
let document:ApplicationDocument
@State var navigationBarIsHidden : Bool = false
var body: some View {
let theView =
NavigationStack(root: {self.generateContentView()})
.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(rawValue: "renewToolbar"), object: self.document), perform: { notification in
self.navigationBarIsHidden = true
Task() {
self.navigationBarIsHidden = false
}})
return theView
}
func generateContentView() -> some View {
let theView =
Text("This is my content view")
.toolbar {self.generateToolBar()}
.navigationBarHidden(self.navigationBarIsHidden)
}
@ToolbarContentBuilder
func generateToolBar() -> some ToolbarContent {
ToolbarItem(placement: .navigationBarTrailing) {
Text("This is a toolbar item")
}
}
}
问题仍然存在:如果各种事件都可能导致导航栏消失,那么我应该在什么时候发送这个通知呢?解决方案是将其绑定到工具栏项目本身的.onDisappear修饰符上。
所以这是完整的代码:
struct ContentView: View {
let document:ApplicationDocument
@State var navigationBarIsHidden : Bool = false
var body: some View {
let theView =
NavigationStack(root: {self.generateContentView()})
.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name(rawValue: "renewToolbar"), object: self.document), perform: { notification in
self.navigationBarIsHidden.toggle()
Task() {
self.navigationBarIsHidden.toggle()
}})
return theView
}
func generateContentView() -> some View {
let theView =
Text("This is my content view")
.toolbar {self.generateToolBar()}
.navigationBarHidden(self.navigationBarIsHidden)
}
@ToolbarContentBuilder
func generateToolBar() -> some ToolbarContent {
ToolbarItem(placement: .navigationBarTrailing) {
Text("This is a toolbar item")
.onDisappear(perform: {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "renewToolbar"), object: self.document)
})
}
}
}
在我的实际应用中,通知实际上是绑定到一个TextField(搜索框)而不是Text,以防万一这不是为了Text而调用的。
结果是,当我关闭弹出视图时,工具栏仍然消失,但随后立即重新出现。
我尝试了上面提出的使用视图的id进行更新的解决方案,但对我来说没有起作用。在SwiftUI中,替换id是一项繁重的操作,因为它会强制重新渲染整个视图层次结构。整个视图(在我的情况下:整个屏幕)都会重新构建。