小编典典

在SwiftUI中以编程方式检测Tab栏或TabView的高度

swift

我有一个SwiftUI应用程序,它将具有一个浮动播客播放器,类似于位于选项卡栏上方的Apple
Music播放器,并且在播放器运行时在所有选项卡和视图中均保持不变。我还没有找到一种好的方法来放置播放器,使其处于Tab栏上方,因为Tab栏的高度随设备而异。我发现的主要问题是如何将播放器放置在应用程序根视图中的叠加层或ZStack中,而不是在TabView本身中。由于我们无法自定义TabView布局的视图层次结构,因此无法在TabBar本身及其上方的视图内容之间注入视图。我的基本代码结构:

TabView(selection: $appState.selectedTab){
  Home()
  .tabItem {
    VStack {
        Image(systemName: "house")
        Text("Home")
    }
  }
  ...
}.overlay(
  VStack {
    if(audioPlayer.isShowing) {
      Spacer()
      PlayerContainerView(player: audioPlayer.player)
      .padding(.bottom, 58)
      .transition(.moveAndFade)
    }
  })

这里的主要问题是PlayerContainerView的位置是硬编码的,填充为58,以便清除TabView。如果我可以检测到TabView的实际框架高度,则可以针对给定设备进行全局调整,这样就可以了。有人知道如何可靠地做到这一点吗?还是您有任何想法如何将PlayerContainerView放置在TabView本身内,以便在切换显示时仅显示在Home()视图和Tab栏之间?对于任何反馈,我们都表示感谢。


阅读 1012

收藏
2020-07-07

共1个答案

小编典典

由于正式允许并记录了与UIKit的桥梁,因此可以在需要时从那里读取所需的信息。

这是直接从中读取标签栏高度的可能方法 UITabBar

// Helper bridge to UIViewController to access enclosing UITabBarController
// and thus its UITabBar
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)
            }
        }
    }
}

// Demo SwiftUI view of usage
struct TestTabBar: View {
    var body: some View {
        TabView {
            Text("First View")
                .background(TabBarAccessor { tabBar in
                    print(">> TabBar height: \(tabBar.bounds.height)")
                    // !! use as needed, in calculations, @State, etc.
                })
                .tabItem { Image(systemName: "1.circle") }
                .tag(0)
            Text("Second View")
                .tabItem { Image(systemName: "2.circle") }
                .tag(1)
        }
    }
}
2020-07-07