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
代码:
在我上次
再次感谢@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
代码: