ios - GeometryReader 仍然考虑到宿主控制器的隐藏导航栏
问题描述
我有一个UIHostingController
隐藏导航栏的子类viewDidLoad
。在我的主机控制器中,我有一个 SwiftUI 视图,它使用几何阅读器来计算顶部安全区域插图。不幸的是,我认为几何读者仍然认为导航栏是可见的,因此报告了错误的顶部安全区域插图大小。我如何让它报告正确的插图?这是我的代码:
final class NavigationHostingController<Content: View>: UIHostingController<Content> {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isHidden = true
}
}
struct AccountDetailsView: View {
var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
Color.yellow
.edgesIgnoringSafeArea(.all)
.frame(height: geometry.safeAreaInsets.top)
// some other views
}
}
}
}
let viewController = NavigationHostingController(rootView: accountDetailsView)
navigationController?.pushViewController(viewController, animated: true)
解决方案
UIHostingController 不会忽略安全区域插图,这似乎是一个错误。有一种方法可以通过调整 UIHostingController 的安全区域方法来解决问题,这样我们就可以返回以下插图.zero
:
final class NavigationHostingController<Content: View>: UIHostingController<Content> {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isHidden = true
disableSafeArea()
}
private func disableSafeArea() {
guard let viewClass = object_getClass(view) else { return }
let viewSubclassName = String(cString: class_getName(viewClass)).appending("_IgnoreSafeArea")
if let viewSubclass = NSClassFromString(viewSubclassName) {
object_setClass(view, viewSubclass)
}
else {
guard let viewClassNameUtf8 = (viewSubclassName as NSString).utf8String else { return }
guard let viewSubclass = objc_allocateClassPair(viewClass, viewClassNameUtf8, 0) else { return }
if let method = class_getInstanceMethod(UIView.self, #selector(getter: UIView.safeAreaInsets)) {
let safeAreaInsets: @convention(block) (AnyObject) -> UIEdgeInsets = { obj in
if var insets = (obj as? UIView)?.superview?.safeAreaInsets {
insets.top = 0
return insets
} else {
return .zero
}
}
class_addMethod(viewSubclass, #selector(getter: UIView.safeAreaInsets), imp_implementationWithBlock(safeAreaInsets), method_getTypeEncoding(method))
}
objc_registerClassPair(viewSubclass)
object_setClass(view, viewSubclass)
}
}
}