如何完全删除 NavigationView 中的 Navbar

How to delete Navbar in NavigationView at all

我已经 当我从 API 获取数据时,如何在使用 页面样式 TabView 时摆脱超出范围的索引错误.有人建议我这样做:

Add an if rockets.isEmpty clause around the entire TabView and display something else if the array is empty (like a loading indicator)

// MARK: - API
class InfoApi {
    func getRockets(completion: @escaping ([RocketInfo]) -> ()) {
        guard let url = URL(string: "https://api.spacexdata.com/v4/rockets") else {
            return
        }
        
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            do {
                let rocketsInfo = try JSONDecoder().decode([RocketInfo].self, from: data!)
                DispatchQueue.main.async {
                    completion(rocketsInfo)
                }
            } catch {
                print(error.localizedDescription)
            }
        }
        .resume()
    }
}

// MARK: - ROCKET MODEL
struct RocketInfo: Codable, Identifiable {
    let id = UUID()
    let name: String
    let country: String
}

// MARK: - CONTENT VIEW
struct ContentView: View {
    @State var rockets: [RocketInfo] = []
    
    var body: some View {
        Group {
            if rockets.isEmpty {
                ProgressView()
            } else {
                NavigationView {
                    TabView {
                        ForEach(rockets) { rocket in
                            ScrollView(.vertical, showsIndicators: false) {
                                VStack(alignment: .center) {
                                    Image(systemName: "globe")
                                        .renderingMode(.original)
                                        .resizable()
                                        .scaledToFit()
                                        .frame(height: 190, alignment: .center)
                                    
                                    ZStack {
                                        RoundedRectangle(cornerRadius: 32)
                                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 865, maxHeight: .infinity, alignment: .center)
                                            .foregroundColor(Color.gray)
                                        
                                        VStack(spacing: 40) {
                                            HStack {
                                                Text("Name")
                                                    .font(.title)
                                                Spacer()
                                                Text(rocket.name)
                                                    .font(.title)
                                            }
                                        } //: VSTACK
                                        .padding(.horizontal)
                                    } //: ZSTACK
                                } //: VSTACK
                                .navigationBarTitleDisplayMode(.inline)
                                .navigationBarHidden(true)
                            } //: SCROLL
                        } //: LOOP
                    } //: TAB
                    .tabViewStyle(.page)
                    .edgesIgnoringSafeArea(.vertical)
                } //: NAVIGATION
            }
        } //: GROUP
        .onAppear {
            InfoApi().getRockets { rockets in
                self.rockets = rockets
            }
        }
        .edgesIgnoringSafeArea(.vertical)
    }
}

// MARK: - PREVIEW
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

它有所帮助,但还有另一个问题。要将 TabView 包装在 if-else 子句中,我必须在其外部添加一些其他视图(例如,NavigationView)并调用 onAppear 这个视图的方法使一切正常。问题是我无法完全删除 NavigationView.

顶部的白色安全区域

That's what it looks like in the Simulator

如果我将 TabView 包装在 HStack 而不是 NavigationView 中,然后将 ScrollView 滚动到最后看到最底下有个白条,也不知道怎么去掉。

This white space at the bottom of the ScrollView I was talking about

对此有许多可能的解决方案。所有这些都涉及摆脱 NavigationView,因为看起来您唯一的用途就是需要某种包装视图。

解决方案 #1: 将您的 isEmpty 支票移到 TabView

var body: some View {
  TabView {
    if rockets.isEmpty {
      //ProgressView
    } else {
      //your tabs
    }
  }.onAppear {
    //API call
  }
}

解决方案#2: 将您的内容包装在 Group:

中,而不是 NavigationView
var body: some View {
  Group {
    if !rockets.isEmpty {
      TabView { /*...*/ }
    }
  }.onAppear {
    //API call
  }
}

解决方案 #3:在进度视图出现时调用 onAppear

if rockets.isEmpty {
  ProgressView()
   .onAppear {
     //API call
   }
} else {
  TabView {
    //tab content
  }
}

编辑:带有模拟的完整示例 objects/API

struct TabBarView: View {
    @State var rockets: [RocketInfo] = []
    
    var body: some View {
        Group {
            if rockets.isEmpty {
                ProgressView()
            } else {
                NavigationView {
                    TabView {
                        
                        ForEach(rockets) { rocket in
                            Text(rocket.title)
                        }
                        
                    }
                    .tabViewStyle(.page)
                }
            }
        }
        .onAppear {
            InfoApi().getRockets { rockets in
                self.rockets = rockets
            }
        }
    }
}

不幸的是,事实证明,如果在一个视图中同时使用 TabBar 和 NavigationView,则完全不可能摆脱导航栏。