SwiftUI - 带有自定义视图的 TabView 覆盖

SwiftUI - TabView Overlay with custom view

在我上次 中,我询问了一种在 SwiftUI 中实现以下 TabView 覆盖的方法:

再次感谢@davidev 的快速支持。

我修改了解决方案,并有机会应用条件视图修饰符。在这种情况下 .overlay().

extension View {
    @ViewBuilder
    func `if`<Content: View>(_ condition: Bool, content: (Self) -> Content) -> some View {
        if condition {
            content(self)
        }
        else {
            self
        }
    }
}

上面截取的代码使我能够实现在切换 observedObject 时显示的条件工具栏(例如,通过从读取模式切换到编辑模式):

.if(class.observedObject){ view in
    view.overlay(ToolbarFromDavidev())
}

这也有效,但它确实有问题(例如,整个视图导航被重置并且我限制了样式设置的机会)。

这引出了我的问题:你们中有人有我可以用来指导的参考实现吗?我想用 ZStack 解决这个问题,我可以将它定位在我用于导航的 TabView 上。就像上面的 GIF 中显示的那样。但是,我无法将 ZStack 置于 TabView 之上。已经尝试过忽略安全区域等方法

非常感谢!

您可以像这样覆盖 TabView:

TabView {
    ...
}
.overlay(
    VStack {
        Spacer()
        
        //Your View
            .frame(height: /*Height of the TabBar*/)
    }
    .edgesIgnoringSafeArea(.all)
)        

现在归结为找出 TabBar 的高度。由于它是动态的(不同 iPhone 屏幕尺寸),一种方式是这样的:

@State private var tabBarHeight: CGFloat = .zero
...

TabView {
    //NavigationView
        .background(
            TabBarAccessor { tabBar in tabBarHeight = tabBar.bounds.height }
        )
}
.overlay(
    VStack {
        Spacer()
        
        //Your View
            .frame(height: tabBarHeight)
    }
    .edgesIgnoringSafeArea(.all)
) 

示例解决方案

一切都在一起 - 您的第一个答案中的代码已修改。

代码:

struct ContentView: View {
    
    @State private var tabBarHeight: CGFloat = .zero
    @State var isSelecting : Bool = false
    
    var body: some View {
        TabView {
            NavigationView {
                Text("First Nav Page")
            }
            .tabItem {
                Image(systemName: "house")
                Text("Home")
                
            }.tag(0)
            .background(
                TabBarAccessor { tabBar in tabBarHeight = tabBar.bounds.height }
            )
            
            NavigationView {
                Text("Second Nav Page")
            }
            .tabItem {
                Image(systemName: "gear")
                Text("Settings")
            }.tag(1)
            
            Text("No Nav Page")
                .tabItem{
                    Image(systemName: "plus")
                    Text("Test")
                }.tag(2)
        }
        .overlay(
            VStack {
                Spacer()
                Rectangle()
                    .foregroundColor(.green)
                    .frame(height: tabBarHeight)
            }
            .edgesIgnoringSafeArea(.all)
        )
    }
}

struct TabBarAccessor: UIViewControllerRepresentable {
    var callback: (UITabBar) -> Void
    private let proxyController = ViewController()

    func makeUIViewController(context: UIViewControllerRepresentableContext<TabBarAccessor>) ->
                              UIViewController {
        proxyController.callback = callback
        return proxyController
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<TabBarAccessor>) {
    }

    typealias UIViewControllerType = UIViewController

    private class ViewController: UIViewController {
        var callback: (UITabBar) -> Void = { _ in }

        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            if let tabBar = self.tabBarController {
                self.callback(tabBar.tabBar)
            }
        }
    }
}

备注

我从以下位置找到的 TabBarAccessor 代码: