SwiftUI中,当跟随NavigationLink并返回后,.toolbar消失了。

18

我在NavigationView的顶层添加了一个.toolbar,最终将用于选择列表中的项目而不使用滑动手势(上按钮、下按钮等)。此外,我还有一个.navigationBar,可以访问其他视图以获取账户和设置。

大部分看起来都很好,但是当我跟随NavigationView中的NavigationLink(在.navigationBarItems中)并使用内置的返回导航时,我的.toolbar会从顶层消失。

我是否将.toolbar放错了位置?感觉这是与.navigationViewStyle(StackNavigationViewStyle())有关的问题,因为当我注释掉它时,工具栏在导航时不会消失...但我不喜欢默认行为在横向模式下的效果,所以我依赖它。


import SwiftUI

struct ContentView: View {

    var body: some View {

                NavigationView {

                    List {
                        Group {
                            Section(header: Text("List Items").foregroundColor(.gray).font(.footnote)) {
                                Text("List Item One")
                                Text("List Item Two")
                                Text("List Item Three")
                            }
                        }
                   }.navigationTitle("Top Level List").navigationBarTitleDisplayMode(.inline)
                       .ignoresSafeArea(.all)

    // MARK: NAVBAR

                        .navigationBarItems(
                            leading:
                            NavigationLink(destination: UserView()) {
                                Image(systemName: "person.crop.circle").font(.title2)
                            },
                            trailing:
                                NavigationLink(destination: SettingsView()) {
                                    Image(systemName: "gear").font(.title2)
                                })

     //MARK: - CONTENT NAV

                        .toolbar {

                            ToolbarItemGroup(placement: .bottomBar) {

                                Button(action: {}, label: {Label("Mute", systemImage: "speaker.slash.fill")})
                                Spacer()
                                Button(action: {}, label: {Label("Repeat", systemImage: "arrow.clockwise")})
                                Spacer()
                                Button(action: {}, label: {Label("Previous", systemImage: "arrow.up")})
                                Spacer()
                                Button(action: {}, label: {Label("Next", systemImage: "arrow.down")})
                                Spacer()
                                Button(action: {}, label: {Label("Select", systemImage: "arrow.right")})

                            }
                        }
                }.navigationViewStyle(StackNavigationViewStyle())
        }
}

struct UserView: View {

    @State private var username: String = ""
    @State private var password: String = ""

    var body: some View {

                    Form {
                        TextField("Username", text: $username)
                        SecureField("Password", text: $password)
                    }
                    .navigationBarTitle("Account").font(.subheadline)

    }
}

struct SettingsView: View {
    
    @State private var setting1: String = ""
    @State private var setting2: String = ""

    var body: some View {

        Form {
            TextField("Setting One", text: $setting1)
            SecureField("Setting Two", text: $setting2)
        }
        .navigationBarTitle("Settings").font(.subheadline)

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1
请查看已找到的解决方法 https://dev59.com/gL7pa4cB1Zd3GeqPy3KT#65127277 - Asperi
2个回答

1
你说得对,它放错了位置。如果你需要始终显示工具栏,应该这样做:
```html

你的代码

```
请注意,代码应该放在上面的标签内。
struct ContentView: View {
    
    var body: some View {
        
        NavigationView {
            
            List {
                Group {
                    Section(header: Text("List Items").foregroundColor(.gray).font(.footnote)) {
                        Text("List Item One")
                        Text("List Item Two")
                        Text("List Item Three")
                    }
                }
            }.navigationTitle("Top Level List").navigationBarTitleDisplayMode(.inline)
                .ignoresSafeArea(.all)
            
            // MARK: NAVBAR
            
                .navigationBarItems(
                    leading:
                        NavigationLink(destination: UserView()) {
                            Image(systemName: "person.crop.circle").font(.title2)
                        },
                    trailing:
                        NavigationLink(destination: SettingsView()) {
                            Image(systemName: "gear").font(.title2)
                        })
            
            //MARK: - CONTENT NAV
            
        }.navigationViewStyle(StackNavigationViewStyle())
            .toolbar {
                
                ToolbarItemGroup(placement: .bottomBar) {
                    
                    Button(action: {}, label: {Label("Mute", systemImage: "speaker.slash.fill")})
                    Spacer()
                    Button(action: {}, label: {Label("Repeat", systemImage: "arrow.clockwise")})
                    Spacer()
                    Button(action: {}, label: {Label("Previous", systemImage: "arrow.up")})
                    Spacer()
                    Button(action: {}, label: {Label("Next", systemImage: "arrow.down")})
                    Spacer()
                    Button(action: {}, label: {Label("Select", systemImage: "arrow.right")})
                    
                }
            }
    }
}

0
我找到了一种更适合SwiftUI和iOS的方法来解决在SwiftUI和iOS中导航栏(工具栏)消失的问题。 我使用工具栏来执行非常重要的命令 - 这是macOS中应用程序菜单的替代品。因此,没有工具栏会削弱我的iOS应用程序。它绝对不应该发生。然而,各种情况导致它消失(比如当我关闭弹出视图或在主视图中滚动时)。为此,我似乎找到了一个可靠的解决方案。 首先是生成工具栏的模板代码 - 这是生成我的应用程序基本内容视图的象征性代码。
struct ContentView: View {
   
   var body: some View {
      
      // The NavigationStack ensures the presence of the navigationBar (toolBar)
      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 {
      
      // The NavigationStack ensures the presence of the navigationBar (toolBar)
      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() {@MainActor () -> Void in 
            try? await Task.sleep(for:.milliseconds(1000))
               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 {
      
      // The NavigationStack ensures the presence of the navigationBar (toolBar)
      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() {@MainActor () -> Void in
            try? await Task.sleep(for:.milliseconds(1000)) 
               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是一项繁重的操作,因为它会强制重新渲染整个视图层次结构。整个视图(在我的情况下:整个屏幕)都会重新构建。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接