From bc1d1b21389837bb9348e86000014f11e56bbbd3 Mon Sep 17 00:00:00 2001 From: Luke Zhao Date: Wed, 30 Oct 2024 15:14:02 -0700 Subject: [PATCH] add a content inset setter helper --- .../UIView+ComponentEngine.swift | 30 ++++++++++++++++++- .../Extensions/UIScrollView+UIComponent.swift | 15 ++++------ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Sources/UIComponent/Core/ComponentView/UIView+ComponentEngine.swift b/Sources/UIComponent/Core/ComponentView/UIView+ComponentEngine.swift index 36ddd579..d244d05e 100644 --- a/Sources/UIComponent/Core/ComponentView/UIView+ComponentEngine.swift +++ b/Sources/UIComponent/Core/ComponentView/UIView+ComponentEngine.swift @@ -19,6 +19,7 @@ extension UIView { _ = UIView.swizzle_layoutSubviews _ = UIView.swizzle_sizeThatFits _ = UIScrollView.swizzle_safeAreaInsetsDidChange + _ = UIScrollView.swizzle_setContentInset _componentEngine = componentEngine return componentEngine } @@ -69,7 +70,7 @@ extension UIView { } static let swizzle_setBounds: Void = { - guard let originalMethod = class_getInstanceMethod(UIView.self, NSSelectorFromString("setBounds:")), + guard let originalMethod = class_getInstanceMethod(UIView.self, #selector(setter: bounds)), let swizzledMethod = class_getInstanceMethod(UIView.self, #selector(swizzled_setBounds(_:))) else { return } method_exchangeImplementations(originalMethod, swizzledMethod) @@ -89,6 +90,13 @@ extension UIScrollView { method_exchangeImplementations(originalMethod, swizzledMethod) }() + static let swizzle_setContentInset: Void = { + guard let originalMethod = class_getInstanceMethod(UIScrollView.self, #selector(setter: contentInset)), + let swizzledMethod = class_getInstanceMethod(UIScrollView.self, #selector(swizzled_setContentInset(_:))) + else { return } + method_exchangeImplementations(originalMethod, swizzledMethod) + }() + @objc func swizzled_safeAreaInsetsDidChange() { guard responds(to: #selector(swizzled_safeAreaInsetsDidChange)) else { return } swizzled_safeAreaInsetsDidChange() @@ -96,5 +104,25 @@ extension UIScrollView { componentEngine.setNeedsReload() } } + + @objc func swizzled_setContentInset(_ contentInset: UIEdgeInsets) { + // when contentOffset is at the top, and contentSize is set + // changing contentInset will not trigger a contentOffset change + // we manually adjust the contentOffset back to the top + // same for the horizontal axis + let yAtTop = contentOffset.y <= -adjustedContentInset.top + let xAtLeft = contentOffset.x <= -adjustedContentInset.left + swizzled_setContentInset(contentInset) + var newContentOffset = contentOffset + if yAtTop { + newContentOffset.y = -adjustedContentInset.top + } + if xAtLeft { + newContentOffset.x = -adjustedContentInset.left + } + if newContentOffset != contentOffset { + contentOffset = newContentOffset + } + } } diff --git a/Sources/UIComponent/Extensions/UIScrollView+UIComponent.swift b/Sources/UIComponent/Extensions/UIScrollView+UIComponent.swift index ca9a9759..4742a574 100644 --- a/Sources/UIComponent/Extensions/UIScrollView+UIComponent.swift +++ b/Sources/UIComponent/Extensions/UIScrollView+UIComponent.swift @@ -17,17 +17,12 @@ extension UIScrollView { } public var offsetFrame: CGRect { - let contentInset: UIEdgeInsets - if #available(iOS 11.0, *) { - contentInset = adjustedContentInset - } else { - contentInset = self.contentInset - } + let inset = adjustedContentInset return CGRect( - x: -contentInset.left, - y: -contentInset.top, - width: max(0, contentSize.width - bounds.width + contentInset.right + contentInset.left), - height: max(0, contentSize.height - bounds.height + contentInset.bottom + contentInset.top) + x: -inset.left, + y: -inset.top, + width: max(0, contentSize.width - bounds.width + inset.right + inset.left), + height: max(0, contentSize.height - bounds.height + inset.bottom + inset.top) ) }