Swift UITableViewHeaderFooterView,具有快速UI内容,可自动插入安全区域

Swift UITableViewHeaderFooterView,具有快速UI内容,可自动插入安全区域,swift,uitableview,swiftui,uitableviewsectionheader,Swift,Uitableview,Swiftui,Uitableviewsectionheader,我有一个带有一些单元格的基本UITableView。我正在使用SwiftUI视图作为单元格和节标题的内容。奇怪的是,在iPhone XS Max上,只有看起来触屏底部的部分标题似乎得到了16pts的rawsafeainset(选中的调试视图层次结构)。我的手机工作正常 为了了解其中的情况,我在contentView中添加了一个虚拟的蓝色快速UI矩形,然后在顶部放置了一个红色UIView,两个视图设置为相同的约束。已将UITableView设置为对标题和单元格使用自动标注 public class

我有一个带有一些单元格的基本
UITableView
。我正在使用SwiftUI
视图
作为单元格和节标题的内容。奇怪的是,在iPhone XS Max上,只有看起来触屏底部的部分标题似乎得到了16pts的
rawsafeainset
(选中的调试视图层次结构)。我的手机工作正常

为了了解其中的情况,我在
contentView
中添加了一个虚拟的蓝色快速UI矩形,然后在顶部放置了一个红色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),
    ])
  }
}
我该如何去掉这个插图?正如我所提到的,这只发生在
UITableViewHeaderFooterView
s上,而不是
UITableViewCell
s上

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


在这个子类
UIHostingController
中托管视图为我做到了这一点

//https://twitter.com/b3ll/status/1193747288302075906
类FixSafeAreaInsertHostingViewController:UIHostingController{
func fixappliced()->Self{
self.fixafeareainsets()
回归自我
}
func FixSafeArea插图(){
guard let\u class=view?.classForCoder-else{
法塔莱罗()
}
让安全区域插入:@convention(block)(AnyObject)->UIEdgeInsets={(sself:AnyObject!)->UIEdgeInsets in
返回,零
}
guard let method=class_getInstanceMethod(_class.self,#选择器(getter:UIView.safeAreaInsets))else{return}
class_replaceMethod(_class,#选择器(getter:UIView.safeAreaInsets),imp_实现WithBlock(safeAreaInsets),method_getTypeEncoding(method))
让safeAreaLayoutGuide:@convention(block)(AnyObject)->UILayoutGuide?={(self:AnyObject!)->UILayoutGuide?返回nil}
guard let method2=class_getInstanceMethod(_class.self,#选择器(getter:UIView.safeAreaLayoutGuide))else{return}
class_replaceMethod(_class,#选择器(getter:UIView.safeAreaLayoutGuide),imp_实现WithBlock(safeAreaLayoutGuide),方法_getTypeEncoding(method2))
}
覆盖变量prefersStatusBarHidden:Bool{
返回错误
}
}

我在UICollectionView中遇到了类似的问题,并修复了以下自定义UIHostingController,该控制器具有
ViewSafeAreaInsettsDidChange
覆盖方法

class TopInsetCounterHostingController<ContentView: SwiftUI.View>: UIHostingController<ContentView> {
    override func viewSafeAreaInsetsDidChange() {
        additionalSafeAreaInsets = .init(top: view.safeAreaInsets.bottom, left: 0, bottom: 0, right: 0)
    }
}
类TopInsertCounterHostController:UIHostingController{
覆盖func viewSafeAreaInsetsDidChange(){
additionalSafeAreaInsets=.init(顶部:view.safeAreaInsets.bottom,左侧:0,底部:0,右侧:0)
}
}
我发现内容视图向上移动的幅度与安全区域的底部插图一样大,因此尝试使用该值调整顶部插图。最终得到了我期望的结果。顶部插图使视图移回预期位置


不幸的是,我不能给你任何明确的解释它是如何在引擎盖下工作的,因为我缺乏这方面的知识。这只是我尝试过的很多实验得出的结果。希望它对任何正在使用它的人都有用。

当我不将UIHostingController添加到父视图控制器时,这个问题就消失了。我不是说这是正确的解决方案,但它可能比swizzling解决方案更好。

我认为这是一个SwiftUI错误。我现在已经报告了它,并在UIKit中重新编写了布局,因为现在看来这是不可避免的。令人沮丧的是,UIHostingView上有一个var
disableSafeArea:Bool
,但由于它是一个私有类,我们无法设置它:(我想这就是他们在列表等的实现中使用的方法。谢谢!这看起来是唯一的解决方案,但非常有黑客性。我个人不喜欢swizzling方法。如果将此作为一个bug记录在Apple中也会很好(我已经有了)因此,投票越多,他们就越早修复此问题。请注意,这将适用于所有swiftUI托管控制器。如果您仅在UIKit应用程序中的组件中使用swiftUI,是否会有此技巧
class TopInsetCounterHostingController<ContentView: SwiftUI.View>: UIHostingController<ContentView> {
    override func viewSafeAreaInsetsDidChange() {
        additionalSafeAreaInsets = .init(top: view.safeAreaInsets.bottom, left: 0, bottom: 0, right: 0)
    }
}