locking UIScrollView

Updated
Oct 6, 2021 2:47 PM
Created
Oct 6, 2021 2:45 PM
Tags
SwiftCocoaiOS

final class ScrollController {

  private var scrollObserver: NSKeyValueObservation!
  private(set) var isLocking: Bool = false
  private var previousValue: CGPoint?

  init(scrollView: UIScrollView) {
    scrollObserver = scrollView.observe(\.contentOffset, options: .old) { [weak self, weak _scrollView = scrollView] scrollView, change in

      guard let scrollView = _scrollView else { return }
      guard let self = self else { return }
      self.handleScrollViewEvent(scrollView: scrollView, change: change)
    }
  }

  deinit {
    endTracking()
  }

  func lockScrolling() {
    isLocking = true
  }

  func unlockScrolling() {
    isLocking = false
  }

  func endTracking() {
    unlockScrolling()
    scrollObserver.invalidate()
  }

  private func handleScrollViewEvent(scrollView: UIScrollView, change: NSKeyValueObservedChange<CGPoint>) {

    // For debugging

    guard let oldValue = change.oldValue else { return }

    guard isLocking else {
      return
    }

    guard scrollView.contentOffset != oldValue else { return }

    guard oldValue != previousValue else { return }

    previousValue = scrollView.contentOffset

    scrollView.setContentOffset(oldValue, animated: false)
  }

}