Skip to content

Instantly share code, notes, and snippets.

@noahsmartin
Created July 7, 2023 17:11
Show Gist options
  • Save noahsmartin/1b340c1e99ef077c54c2f798ec05f239 to your computer and use it in GitHub Desktop.
Save noahsmartin/1b340c1e99ef077c54c2f798ec05f239 to your computer and use it in GitHub Desktop.
import Foundation
import UIKit
import SwiftUI
extension UIScrollView {
var visibleContentHeight: CGFloat {
frame.height - (adjustedContentInset.top + adjustedContentInset.bottom)
}
}
extension UIView {
var firstScrollView: UIScrollView? {
var subviews = subviews
while !subviews.isEmpty {
let subview = subviews.removeFirst()
subviews.append(contentsOf: subview.subviews)
if let scrollView = subview as? UIScrollView {
return scrollView
}
}
return nil
}
}
final class ExpandingViewController<Content: View>: UIHostingController<Content> {
private var hasModifiedHeight = false
private var didCall = false
var expansionSettled: (() -> Void)?
private func runCallback() {
guard !didCall else { return }
didCall = true
expansionSettled?()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.updateScrollViewHeight()
}
func updateScrollViewHeight() {
let scrollView = view.firstScrollView
if let scrollView {
let diff = scrollView.contentSize.height - scrollView.visibleContentHeight
if abs(diff) > 0.001 {
if hasModifiedHeight || diff > 0 {
hasModifiedHeight = true
view.frame = CGRect(x: view.frame.minX, y: view.frame.minY, width: view.frame.width, height: view.frame.height + diff)
} else {
runCallback()
}
} else {
runCallback()
}
} else {
runCallback()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment