我正在使用SwiftUI,并且TabBar出现了一些问题。 我想在特定的子视图上隐藏TabBar。
尝试过
UITabBar.appearance().isHidden = true
它仅适用于TabView中的直接视图。但是,当我将其放置在子视图中时,它不起作用。
有人对此有解决方案吗?
谢谢。
答案 0 :(得分:7)
安装Introspect SwiftPM:https://github.com/siteline/SwiftUI-Introspect
var body: some View {
List {
-your code here-
}
.navigationBarTitle("Title", displayMode: .inline)
.introspectTabBarController { (UITabBarController) in
UITabBarController.tabBar.isHidden = true
}
}
注意:您必须在父视图中重新启用TabBar,否则它仍将被隐藏。
.introspectTabBarController { (UITabBarController) in
UITabBarController.tabBar.isHidden = false
}
答案 1 :(得分:5)
它正在工作,只需要在主队列上调用更改
struct ShowTabBar: ViewModifier {
func body(content: Content) -> some View {
return content.padding(.zero).onAppear {
DispatchQueue.main.async {
Tool.showTabBar()
}
}
}
}
struct HiddenTabBar: ViewModifier {
func body(content: Content) -> some View {
return content.padding(.zero).onAppear {
DispatchQueue.main.async {
Tool.hiddenTabBar()
}
}
}
}
遍历窗口的allsubview以隐藏UITabBar。您可以将其编写为ViewModifier并在SwiftUI中使用它,也可以使用工具将其隐藏。这种方法对我有用。
extension UIView {
func allSubviews() -> [UIView] {
var res = self.subviews
for subview in self.subviews {
let riz = subview.allSubviews()
res.append(contentsOf: riz)
}
return res
}
}
struct Tool {
static func showTabBar() {
UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.allSubviews().forEach({ (v) in
if let view = v as? UITabBar {
view.isHidden = false
}
})
}
static func hiddenTabBar() {
UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.allSubviews().forEach({ (v) in
if let view = v as? UITabBar {
view.isHidden = true
}
})
}
}
struct ShowTabBar: ViewModifier {
func body(content: Content) -> some View {
return content.padding(.zero).onAppear {
Tool.showTabBar()
}
}
}
struct HiddenTabBar: ViewModifier {
func body(content: Content) -> some View {
return content.padding(.zero).onAppear {
Tool.hiddenTabBar()
}
}
}
extension View {
func showTabBar() -> some View {
return self.modifier(ShowTabBar())
}
func hiddenTabBar() -> some View {
return self.modifier(HiddenTabBar())
}
}
答案 2 :(得分:4)
将 NavigationView 添加为 root 而不是 TabView
NavigationView{
TabView(selection:$selectedIndex) {
}
}
如果您不想在 TabBar 页面中使用 NavigationView,只需将其隐藏即可。
.navigationBarHidden(true)
参考示例项目 - https://github.com/TreatTrick/Hide-TabBar-In-SwiftUI
答案 3 :(得分:2)
我正在使用的基本思想是将ObservableObject和ZStack结合起来。我已经将TabView与条件子视图演示一起放入ZStack。 It's look like。 浏览github repo
答案 4 :(得分:2)
实际上可以通过使用这个方便的小框架为TabView获取底层的UITabbarController:
https://github.com/siteline/SwiftUI-Introspect
该解决方案以MVVM模式为例,以编程方式控制Tabbar的可见性,并能够使用NSNotifications在代码中的任何位置显示,隐藏,启用,禁用表单
SwiftUI视图:像这样设置tabview
struct MainTabView: View {
var viewModel: MainTabViewModel
var body: some View {
TabView() {
Text("View1")
.tabItem {
Text("View1")
}
Text("View2")
.tabItem {
Text("View2")
}
}
.introspectTabBarController { tabBarController in
// customize here the UITabBarViewController if you like
self.viewModel.tabBarController = tabBarController
}
}
}
然后使用ViewModel
final class MainTabViewModel: ObservableObject {
var tabBarController: UITabBarController?
init() {
startListeningNotifications()
}
func startListeningNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(showTabbarView), name: "showBottomTabbar", object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(hideTabbarView), name: "hideBottomTabbar", object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(enableTabbarTouch), name: "enableTouchTabbar", object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(disableTabbarTouch), name: "disableTouchTabbar", object: nil)
}
@objc func showTabbarView() {
self.tabBarController?.tabBar.isHidden = false
}
@objc func hideTabbarView() {
self.tabBarController?.tabBar.isHidden = true
}
@objc func disableTabbarTouch() {
self.tabBarController?.tabBar.isUserInteractionEnabled = false
}
@objc func enableTabbarTouch() {
self.tabBarController?.tabBar.isUserInteractionEnabled = true
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
最后要控制标签栏,只需在您喜欢的地方使用这些功能(将以本示例的模式出现在viewmodel中)
public func showTabbar() {
DispatchQueue.main.async {
NotificationCenter.default.post(name: .showBottomTabbar, object: nil)
}
}
public func hideTabbar() {
DispatchQueue.main.async {
NotificationCenter.default.post(name: .hideBottomTabbar, object: nil)
}
}
public func enableTouchTabbar() {
DispatchQueue.main.async {
NotificationCenter.default.post(name: .enableTouchTabbar, object: nil)
}
}
public func disableTouchTabbar() {
DispatchQueue.main.async {
NotificationCenter.default.post(name: .disableTouchTabbar, object: nil)
}
}
答案 5 :(得分:1)
这里没有隐藏TabView的方法,所以我必须在ZStack中这样添加TabView:
var body: some View {
ZStack {
TabView {
TabBar1().environmentObject(self.userData)
.tabItem {
Image(systemName: "1.square.fill")
Text("First")
}
TabBar2()
.tabItem {
Image(systemName: "2.square.fill")
Text("Second")
}
}
if self.userData.showFullScreen {
FullScreen().environmentObject(self.userData)
}
}
}
UserData:
final class UserData: ObservableObject {
@Published var showFullScreen = false
}
TabBar1:
struct TabBar1: View {
@EnvironmentObject var userData: UserData
var body: some View {
Text("TabBar 1")
.edgesIgnoringSafeArea(.all)
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
.background(Color.green)
.onTapGesture {
self.userData.showFullScreen.toggle()
}
}
}
全屏:
struct FullScreen: View {
@EnvironmentObject var userData: UserData
var body: some View {
Text("FullScreen")
.edgesIgnoringSafeArea(.all)
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
.background(Color.red)
.onTapGesture {
self.userData.showFullScreen.toggle()
}
}
}
检查Github上的完整代码
还有其他一些方法,但这取决于视图的结构
答案 6 :(得分:1)
正确答案是优雅,使用原生 SwiftUI 方法,并允许以任何方式全屏显示任何类型的视图,在任何类型的视图之上是下面。 所有其他答案都使用 3rd-party 包,以不可恢复的方式进入 UIKit 或不优雅。
首先,您需要将要隐藏的视图声明为允许全屏覆盖的视图。一般的想法是,全屏但您想隐藏的视图应该有一个首选项键,用于存储要在其上显示的视图:
/// A preference that allows you to show full screen overlays on top of any top-level full screen view.
///
/// This is particularly useful when trying to present views over a `TabView` or a `NavigationView` which block placing views over
/// their respective safe zones (like the tab bar or the navigation bar).
struct FullScreenCoverPreferenceKey: PreferenceKey {
typealias Value = [OverlayView]
static var defaultValue: [OverlayView] = []
static func reduce(value: inout [OverlayView], nextValue: () -> [OverlayView]) {
value.append(contentsOf: nextValue())
}
/// The underlying overlay view behind the preference key.
struct OverlayView: View, Identifiable {
let id = UUID()
var content: AnyView
init<Content: View>(@ViewBuilder content: () -> Content) {
self.content = AnyView(content())
}
var body: some View {
content
}
}
}
FullScreenCoverPreferenceKey.value
将包含要显示在全屏视图顶部的视图数组(例如 TabView
)。
然后,使用以下方法扩展 View
协议,以便将首选项键附加到视图:
extension View {
/// Declares that this view is capable of receiving full screen overlays.
///
/// - Important
/// This modifier should only be used on views that are taking up the entire screen.
func allowFullScreenOverlays() -> some View {
self
.overlayPreferenceValue(FullScreenCoverPreferenceKey.self) { overlayViewsArray in
ZStack {
ForEach(overlayViewsArray) { overlayView in
overlayView
}
}
}
}
}
将 overlayPreferenceValue
的返回视图呈现为由首选项键的 ZStack
数组组成的 [OverlayView]
允许我们将多个叠加层堆叠在一起。
接下来,创建任何类型的叠加层并将其附加到 TabView 的任何子视图:
ZStack {
Color.white.ignoresSafeArea() //background if needed
TabView {
NavigationView {
ZStack {
NavigationLink(
destination:
ZStack { Color.orange }
.transformPreference(FullScreenCoverPreferenceKey.self) {
$0.append(FullScreenCoverPreferenceKey.OverlayView {
//The overlay
ZStack {
Color.green
Text("I am full screen!")
}
})
},
label: {
Text("Press me to show full screen!")
})
}
}
.tabItem {
Text("Tab")
}
}
}
.allowFullScreenOverlays()
最终视图将如下所示,Tab 被完全覆盖:
答案 7 :(得分:0)
只需使用UIKit的UINavigationController。像这样:
让主机= UINavigationController(rootViewController: UIHostingController(rootView:HLHome()))
答案 8 :(得分:0)
这似乎对我有用。
someSubView{
//your code here
}.onAppear(perform: {
UITabBar.appearance().isHidden = true
})
)
答案 9 :(得分:0)
安装Introspect SwiftPM:https://github.com/siteline/SwiftUI-Introspect
struct SomeView: View{
@State var uiTabarController: UITabBarController?
var body: some View {
List {
-your code here-
}
.navigationBarTitle("Title", displayMode: .inline)
.introspectTabBarController { (UITabBarController) in
UITabBarController.tabBar.isHidden = true
uiTabarController = UITabBarController
}.onDisappear{
uiTabarController?.tabBar.isHidden = false
}
}
}
在uiTabarController
中的这段代码中,我们引用了UITabarController
。当我们返回时,我们再次启用了Tabar
。因此,这就是为什么需要这样做的原因。
答案 10 :(得分:0)
我遇到了同样的问题,最终使用了:
.opacity(hideTabBar == true ? 0 : 1)
其中 hideTabBar 是我传递给需要隐藏 TabBar() 的视图的 Bool。
所以基本上你应该尝试这样的事情:
TabView(selection: your desired tab).opacity(hideTabBar == true ? 0 : 1)
答案 11 :(得分:0)
像这样增加 TabView 的框架大小:
.frame(width: UIScreen.main.bounds.width, height: showTabbar ? UIScreen.main.bounds.height : UIScreen.main.bounds.height + 100.00)
答案 12 :(得分:0)
不理想和笨拙,但对我来说效果很好的最简单的方法是隐藏外部导航视图的导航栏,然后在每个 TabView 的视图中添加另一个导航视图。到目前为止运行良好:
struct LaunchView: View {
var body: some View {
NavigationView {
TabView {
ViewA()
.tabItem {
Label("TabA", systemImage: "some.image")
}
ViewB()
.tabItem {
Label("TabB", systemImage: "some.image")
}
ViewC()
.tabItem {
Label("TabC", systemImage: "some.image")
}
}
.navigationBarHidden(true)
}
}
}
struct ViewA: View {
var body: some View {
NavigationView {
// Content
.navigationTitle("Settings")
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
通过这种方式,您可以在每个单独的视图中设置标题以及 .toolBarItem。
答案 13 :(得分:0)
此解决方案运行良好,除了 SwiftUI.TabView 中的视图修饰符。
由于我的 TabView 在符合 App
的结构中,看起来连接的场景中仍然没有任何 UITabBar
子视图。
使用下面的代码,您只需在 SwiftUI.View 中使用 showTabBar()
或 hiddenTabBar()
。
extension UIApplication {
var key: UIWindow? {
self.connectedScenes
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?
.windows
.filter({$0.isKeyWindow})
.first
}
}
extension UIView {
func allSubviews() -> [UIView] {
var subs = self.subviews
for subview in self.subviews {
let rec = subview.allSubviews()
subs.append(contentsOf: rec)
}
return subs
}
}
struct TabBarModifier {
static func showTabBar() {
UIApplication.shared.key?.allSubviews().forEach({ subView in
if let view = subView as? UITabBar {
view.isHidden = false
}
})
}
static func hideTabBar() {
UIApplication.shared.key?.allSubviews().forEach({ subView in
if let view = subView as? UITabBar {
view.isHidden = true
}
})
}
}
struct ShowTabBar: ViewModifier {
func body(content: Content) -> some View {
return content.padding(.zero).onAppear {
TabBarModifier.showTabBar()
}
}
}
struct HiddenTabBar: ViewModifier {
func body(content: Content) -> some View {
return content.padding(.zero).onAppear {
TabBarModifier.hideTabBar()
}
}
}
extension View {
func showTabBar() -> some View {
return self.modifier(ShowTabBar())
}
func hiddenTabBar() -> some View {
return self.modifier(HiddenTabBar())
}
}
答案 14 :(得分:-2)
此解决方案实际上可在iOS 14上运行
.onAppear(perform: {
UITabBar.appearance().isHidden = true
})