【问题标题】:GeometryReader still takes into account hidden navigation bar of hosting controllerGeometryReader 仍然考虑到宿主控制器的隐藏导航栏
【发布时间】:2021-11-05 03:33:56
【问题描述】:

我有一个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)
        

【问题讨论】:

  • 你需要一个Minimal, Reproducible Example
  • 你是如何使用let viewController = NavigationHostingController(rootView: accountDetailsView)navigationController?.pushViewController(viewController, animated: true)的?

标签: ios swift swiftui


【解决方案1】:

UIHostingController 不会忽略安全区域插入,这似乎是一个错误。有一种方法可以通过swizzling 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)
        }
    }
}

【讨论】:

  • 一个附录:在我的示例代码中,我在 viewDidLoad 中调用了 disableSafeArea(),但根据您的应用,viewDidLoad 可能“为时已晚”,您仍然会看到安全区域。如果发生这种情况,请覆盖 init 并在那里调用 disableSafeArea。
猜你喜欢
  • 2018-04-19
  • 1970-01-01
  • 2014-10-26
  • 2016-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多