UITableViewHeaderFooterView 与 SwiftUI 内容获取自动安全区域插入

str*_*mes 6 uitableview swift uitableviewsectionheader swiftui

UITableView我已经掌握了一些细胞的基础知识。我使用 SwiftUIView作为单元格和节标题的内容。奇怪的是,只有 iPhone XS Max 上似乎接触屏幕底部的部分标题似乎获得了rawSafeAreaInset16 分(检查了“调试视图层次结构”)。我的细胞正在按预期工作。

为了看看发生了什么,我在 中添加了一个虚拟的蓝色 SwiftUI 矩形contentView,然后在顶部放置了一个红色 UIView,两个视图都设置为相同的约束。已UITableView设置为对标题和单元格使用自动尺寸。

public class SectionHeader: UITableViewHeaderFooterView {
  public static let reusableIdentifier = "Section"

  private var innerHostedViewController: UIHostingController<AnyView>!

  public override init(reuseIdentifier: String?) {
    super.init(reuseIdentifier: reuseIdentifier)

    setupHeader()
  }

  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  private func setupHeader() {
    self.backgroundView = UIView()
    self.backgroundView?.backgroundColor = UIColor.green.withAlphaComponent(0.2)

    innerHostedViewController = UIHostingController(rootView: AnyView(Rectangle().fill(Color.blue).frame(height: 48)))
    innerHostedViewController.view.translatesAutoresizingMaskIntoConstraints = false
    innerHostedViewController.view.frame = self.contentView.bounds
    contentView.addSubview(innerHostedViewController.view)
    innerHostedViewController.view.backgroundColor = .clear

    let vv = UIView()
    vv.translatesAutoresizingMaskIntoConstraints = false
    vv.backgroundColor = .red
    contentView.addSubview(vv)

    NSLayoutConstraint.activate([
      vv.topAnchor.constraint(equalTo: self.contentView.topAnchor),
      vv.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor),
      vv.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
      vv.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor),

      innerHostedViewController.view.topAnchor.constraint(equalTo: self.contentView.topAnchor),
      innerHostedViewController.view.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor),
      innerHostedViewController.view.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
      innerHostedViewController.view.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor),
    ])
  }
}
Run Code Online (Sandbox Code Playgroud)

如下图所示,顶部两个标题可见红色覆盖层(带有空单元格用于演示),但屏幕上的最后一个标题的蓝色 SwiftUI 矩形向上移动!

在此输入图像描述

这个 SwiftUI 视图似乎以某种方式获得了一些 safeAreaInset,并且似乎没有办法将其关闭。如果向上滚动,插图也不会消失。它永远留在那里。我尝试关闭 SwiftUI 视图的安全区域插图,但这也没有帮助:

innerHostedViewController = UIHostingController(rootView: AnyView(Rectangle().fill(Color.blue).frame(height: 48).edgesIgnoringSafeArea(.all)))
Run Code Online (Sandbox Code Playgroud)

我如何摆脱这个插图?正如我所提到的 - 它只发生在UITableViewHeaderFooterViews 上,而不发生UITableViewCell在 s 上。

调试视图层次结构显示了基于安全区域插图的虚假底部填充修改器:

在此输入图像描述

And*_*wSB 1

在这个子类中托管视图UIHostingController对我来说很有效!

/// https://twitter.com/b3ll/status/1193747288302075906
class FixSafeAreaInsetsHostingViewController<Content: SwiftUI.View>: UIHostingController<Content> {
    func fixApplied() -> Self {
        self.fixSafeAreaInsets()
        return self
    }

    func fixSafeAreaInsets() {
        guard let _class = view?.classForCoder else {
            fatalError()
        }

        let safeAreaInsets: @convention(block) (AnyObject) -> UIEdgeInsets = { (sself: AnyObject!) -> UIEdgeInsets in
            return .zero
        }
        guard let method = class_getInstanceMethod(_class.self, #selector(getter: UIView.safeAreaInsets)) else { return }
        class_replaceMethod(_class, #selector(getter: UIView.safeAreaInsets), imp_implementationWithBlock(safeAreaInsets), method_getTypeEncoding(method))

        let safeAreaLayoutGuide: @convention(block) (AnyObject) -> UILayoutGuide? = { (sself : AnyObject!) -> UILayoutGuide? in return nil }

        guard let method2 = class_getInstanceMethod(_class.self, #selector(getter: UIView.safeAreaLayoutGuide)) else { return }
        class_replaceMethod(_class, #selector(getter: UIView.safeAreaLayoutGuide), imp_implementationWithBlock(safeAreaLayoutGuide), method_getTypeEncoding(method2))
    }

    override var prefersStatusBarHidden: Bool {
        return false
    }
}
Run Code Online (Sandbox Code Playgroud)