diff --git a/Riot/Modules/Common/SwiftUI/VectorHostingController.swift b/Riot/Modules/Common/SwiftUI/VectorHostingController.swift index c59dc357f..7a6ccaf7a 100644 --- a/Riot/Modules/Common/SwiftUI/VectorHostingController.swift +++ b/Riot/Modules/Common/SwiftUI/VectorHostingController.swift @@ -40,25 +40,20 @@ class VectorHostingController: UIHostingController { var enableNavigationBarScrollEdgeAppearance = false /// When non-nil, the style will be applied to the status bar. var statusBarStyle: UIStatusBarStyle? - - /// Whether to force-set the hosting view's safe area insets to zero. Useful when the view is used as part of a table view. - var forceZeroSafeAreaInsets: Bool { - get { - self.view.forceZeroSafeAreaInsets - } - set { - self.view.forceZeroSafeAreaInsets = newValue - } - } + + private let forceZeroSafeAreaInsets: Bool override var preferredStatusBarStyle: UIStatusBarStyle { statusBarStyle ?? super.preferredStatusBarStyle } - - init(rootView: Content) where Content: View { + /// Initializer + /// - Parameter rootView: Root view for the controller. + /// - Parameter forceZeroSafeAreaInsets: Whether to force-set the hosting view's safe area insets to zero. Useful when the view is used as part of a table view. + init(rootView: Content, + forceZeroSafeAreaInsets: Bool = false) where Content: View { self.theme = ThemeService.shared().theme + self.forceZeroSafeAreaInsets = forceZeroSafeAreaInsets super.init(rootView: AnyView(rootView.vectorContent())) - self.view.swizzleSafeAreaMethodsIfNeeded() } required init?(coder aDecoder: NSCoder) { @@ -106,6 +101,22 @@ class VectorHostingController: UIHostingController { self.view.invalidateIntrinsicContentSize() } } + + override func viewSafeAreaInsetsDidChange() { + super.viewSafeAreaInsetsDidChange() + + guard forceZeroSafeAreaInsets else { + return + } + + let counterSafeAreaInsets = UIEdgeInsets(top: -view.safeAreaInsets.top, + left: -view.safeAreaInsets.left, + bottom: -view.safeAreaInsets.bottom, + right: -view.safeAreaInsets.right) + if additionalSafeAreaInsets != counterSafeAreaInsets, counterSafeAreaInsets != .zero { + additionalSafeAreaInsets = counterSafeAreaInsets + } + } private func registerThemeServiceDidChangeThemeNotification() { NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) @@ -121,83 +132,3 @@ class VectorHostingController: UIHostingController { } } } - -// Hack for forcing zero safe area insets on hosting views. This problem occurs when the hosting view is embedded -// in a table view. See https://stackoverflow.com/questions/61552497 for further info. - -private var hasSwizzledSafeAreaMethods = false -private var forceZeroSafeAreaInsetsKey: Void? - -private extension UIView { - - var forceZeroSafeAreaInsets: Bool { - get { - return objc_getAssociatedObject(self, &forceZeroSafeAreaInsetsKey) as? Bool == true - } - set { - objc_setAssociatedObject(self, &forceZeroSafeAreaInsetsKey, newValue, .OBJC_ASSOCIATION_RETAIN) - } - } - - @objc private var _safeAreaInsets: UIEdgeInsets { - return forceZeroSafeAreaInsets ? .zero : self._safeAreaInsets - } - - @objc private var _safeAreaLayoutGuide: UILayoutGuide? { - return forceZeroSafeAreaInsets ? nil : self._safeAreaLayoutGuide - } - - func swizzleSafeAreaMethodsIfNeeded() { - guard !hasSwizzledSafeAreaMethods else { - return - } - hasSwizzledSafeAreaMethods = true - - guard let getSafeAreaInsets = class_getInstanceMethod(classForCoder.self, #selector(getter: UIView.safeAreaInsets)) else { - return - } - - guard let _getSafeAreaInsets = class_getInstanceMethod(classForCoder.self, #selector(getter: UIView._safeAreaInsets)) else { - return - } - - let getSafeAreaInsetsImplementation = method_getImplementation(getSafeAreaInsets) - let _getSafeAreaInsetsImplementation = method_getImplementation(_getSafeAreaInsets) - - class_replaceMethod( - classForCoder, - #selector(getter: UIView.safeAreaInsets), - _getSafeAreaInsetsImplementation, - method_getTypeEncoding(getSafeAreaInsets)) - - class_replaceMethod( - classForCoder, - #selector(getter: UIView._safeAreaInsets), - getSafeAreaInsetsImplementation, - method_getTypeEncoding(_getSafeAreaInsets)) - - guard let getSafeAreaLayoutGuide = class_getInstanceMethod(classForCoder.self, #selector(getter: UIView.safeAreaLayoutGuide)) else { - return - } - - guard let _getSafeAreaLayoutGuide = class_getInstanceMethod(classForCoder.self, #selector(getter: UIView._safeAreaLayoutGuide)) else { - return - } - - let getSafeAreaLayoutGuideImplementation = method_getImplementation(getSafeAreaLayoutGuide) - let _getSafeAreaLayoutGuideImplementation = method_getImplementation(_getSafeAreaLayoutGuide) - - class_replaceMethod( - classForCoder, - #selector(getter: UIView.safeAreaLayoutGuide), - _getSafeAreaLayoutGuideImplementation, - method_getTypeEncoding(getSafeAreaLayoutGuide)) - - class_replaceMethod( - classForCoder, - #selector(getter: UIView._safeAreaLayoutGuide), - getSafeAreaLayoutGuideImplementation, - method_getTypeEncoding(_getSafeAreaLayoutGuide)) - } - -}