如何在SwiftUI中推出下一个屏幕时隐藏TabBar

3

我希望在用户从下一个屏幕导航时隐藏TabView底部的TabBar。

例如,我有一个TabView,其中包含两个tabItem,比如Home和Account,并且Home屏幕上有一个通知选项,如果用户点击通知,我希望同时导航到通知屏幕,同时隐藏TabView底部的Tab。有没有办法实现这一点?我找不到任何直接的SwiftUI方法来实现这一点。

import SwiftUI

struct MyRootScreen: View {
    var body: some View {
        TabView {
            NavigationView {
                HomeScreen()
            }
            .tabItem {
                Image(systemName: "house")
            }
            
            Text("Account")
                .tabItem {
                    Image(systemName: "person")
                }
        }
    }
}


struct HomeScreen: View {
    @State private var showNotification: Bool = false
    
    var body: some View {
        VStack {
            Button {
                showNotification = true
            } label: {
                Text("Show Notification")
            }
        }
        .overlay {
            NavigationLink("", isActive: $showNotification) {
                Text("Notification Screen")
            }
        }
    }
}

注意:我想在不将TabView包装到NavigationView中的情况下实现这一点。

也许这个链接对你有帮助:https://github.com/TreatTrick/Hide-TabBar-In-SwiftUI - undefined
你也可以使用全屏覆盖。 - undefined
也许 .toolbar(showNotification ? .hidden : .visible, for: .tabBar) - undefined
2个回答

0

所以上面分享了所有可能的方法。但我只是在一个答案中总结它们,并添加了我的建议。

  1. fullScreenCover,根据你的应用程序遵循的导航体验,你可以利用这种方式。
  2. 如果你的部署目标是iOS 14.0,将Tabview嵌入到Navigationview中是另一种选择,但如果你可以使用16.0,你可以尝试使用 .toolbar API 来隐藏tabview。
  3. 因此,在窗口上更改你的rootview也是一个选项,你将不会有tabview与该视图一起显示,但你必须为视图提供动画,当它用你的推送/弹出动画替换在窗口上时,但整体体验可能会因此而丢失,比如没有返回按钮等,那你就需要对所有的事情负责,比如给一个返回按钮及其操作等。

以下是这三种方法的详细信息。

第一种选项是预设一个模态视图或者幕片,显示你的通知视图在那里,但这完全取决于你的导航风格或者应用程序中的其他要求。

使用第二种选项,这是推荐的方法,你可以继续前进,但如果你仅限于iOS 14.0,有16.0你可以尝试使用苹果自己提供的API。

使用第三个选项是可能的,但您必须在该视图上自行管理所有内容,例如提供返回按钮、导航标题和其操作等。
如果您想查看一些示例代码,请参考以下第三种方法。
import SwiftUI

struct ContentView: View {
    @State private var selectedTab = 0
    @EnvironmentObject var viewSwitch: ViewSwitch

    var body: some View {
        if viewSwitch.showRoot == .Tabbed {
            TabView(selection: $selectedTab) {
                AccountView()
                    .environmentObject(viewSwitch)
                    .tabItem {
                        Label("Account", systemImage: "person")
                    }
                    .tag(0)

                GeneralView()
                    .tabItem {
                        Label("General", systemImage: "gear")
                    }
                    .tag(1)
            }
           
        }
        if viewSwitch.showRoot == .WithoutTabbed {
            NotificationsView()
                .transition(.move(edge: .trailing))
        }
    }
}

struct AccountView: View {
    @State private var showNotifications = false
    @State private var isActive = false
    @EnvironmentObject var viewSwitch: ViewSwitch

    var body: some View {
        NavigationView {
            VStack {
                Text("Account View")
                    .font(.largeTitle)
                    .padding()

                Button("Go to Notifications") {
                    showNotifications = true
                    withAnimation(Animation.easeInOut(duration: 0.5)) {
                        viewSwitch.changeRootView(to: .WithoutTabbed)
                    }
                    
                }
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(10)
                .padding()
            }
        }
    }
}

struct GeneralView: View {
    var body: some View {
        VStack {
            Text("General View")
                .font(.largeTitle)
                .padding()
        }
    }
}

struct NotificationsView: View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Notification view")
                    .font(.largeTitle)
                    .padding()
            }
            .navigationBarTitle("Notification", displayMode: .large)
        }
    }
}

@main
struct TestStackOverFlowApp: App {
    let viewSwitch =  ViewSwitch()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(viewSwitch)
        }
    }
}


enum WindowRoot {
    case Tabbed
    case WithoutTabbed
}


class ViewSwitch: ObservableObject {
    public init() {}

    @Published public var showRoot: WindowRoot = .Tabbed
    public func changeRootView(to root: WindowRoot) {
        showRoot = root
    }
}

附上一个工作视频。结果视频 希望对你有所帮助。 在我的Xcode 14.3上运行正常。

0

最好将通知屏幕移动到根视图,并通过布尔标志作为绑定来控制通知。

或者更好的是:由于子视图只需要打开通知,而不需要隐藏,所以可以传递一个函数而不是绑定。它也可以在环境中传递,但要小心保留循环。

这里有一个例子。如果你不需要通知占据整个屏幕,可以用sheet替换fullScreenCover

import SwiftUI

struct MyRootScreen: View {
    @State private var showNotification: Bool = false
    
    var body: some View {
        TabView {
            NavigationView {
                HomeScreen(openNotifications: openNotifications)
            }
            .tabItem {
                Image(systemName: "house")
            }
            
            Text("Account")
                .tabItem {
                    Image(systemName: "person")
                }
        }
        .fullScreenCover(isPresented: $showNotification) {
            NavigationView {
                Text("Notification Screen")
                    .toolbar {
                        ToolbarItem(placement: .navigationBarTrailing) {
                            Button {
                                showNotification = false
                            } label: {
                                Text("Close")
                            }
                        }
                    }
            }
        }
    }
    
    private func openNotifications() {
        showNotification = true
    }
}


struct HomeScreen: View {
    let openNotifications: () -> Void
    
    var body: some View {
        VStack {
            Button {
                openNotifications()
            } label: {
                Text("Show Notification")
            }
        }
    }
}

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