Advertisement
Guest User

Untitled

a guest
Mar 21st, 2019
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 3.94 KB | None | 0 0
  1. import Foundation
  2. import UIKit
  3.  
  4. class ScrollWatcher {
  5.     private weak var scrollView: UIScrollView?
  6.     private var keyObservation: NSKeyValueObservation!
  7.     private var range: ClosedRange<CGFloat>
  8.     var topBounces: Bool
  9.     var bottomBounces: Bool
  10.     private var cancelsInRange: Bool
  11.     private var watchOnlyDelta: Bool
  12.     private var update: (CGFloat) -> ()
  13.    
  14.     private var current: CGFloat = 0
  15.    
  16.     private var lastUpdateValue = CGFloat.infinity
  17.    
  18.     private static var stopRecursive = false
  19.    
  20.     init(
  21.         _ scrollView: UIScrollView,
  22.         _ range: ClosedRange<CGFloat>,
  23.         _ bounces: Bool,
  24.         _ cancelsInRange: Bool,
  25.         _ watchOnlyDelta: Bool,
  26.         _ update: @escaping (_ t: CGFloat) -> ()) {
  27.         self.scrollView = scrollView
  28.         self.range = range
  29.         self.topBounces = bounces
  30.         self.bottomBounces = bounces
  31.         self.cancelsInRange = cancelsInRange
  32.         self.watchOnlyDelta = watchOnlyDelta
  33.         self.update = update
  34.         current = self.range.lowerBound
  35.        
  36.         keyObservation = self.scrollView?.observe(\.contentOffset, options: [.new, .old]) {
  37.             [weak self] scrollView, changedValue in
  38.             guard let `self` = self, !ScrollWatcher.stopRecursive, self.scrollView != nil else { return }
  39.             let value = changedValue.newValue!.y
  40.             let oldValue = changedValue.oldValue!.y
  41.             let delta = value - oldValue
  42.            
  43.             let scrollContentSize = scrollView.contentSize
  44.             let scrollViewSize = scrollView.frame.size
  45.            
  46.             let watchValueTopBound = value >= self.range.lowerBound || !self.topBounces
  47.             let watchValueBottomBound = value <= self.range.upperBound || !self.bottomBounces
  48.             let watchValue = watchValueTopBound || watchValueBottomBound
  49.             let watchCurrentTopBound = self.current >= self.range.lowerBound || !self.topBounces
  50.             let watchCurrentBottomBound = self.current <= self.range.upperBound || !self.bottomBounces
  51.             let watchCurrent = watchCurrentTopBound && watchCurrentBottomBound
  52.            
  53.             if watchValue && !watchOnlyDelta || watchOnlyDelta, watchCurrent {
  54.                 var delta = delta
  55.                 if oldValue <= self.range.lowerBound, self.topBounces && !self.watchOnlyDelta {
  56.                     delta = value - self.range.lowerBound
  57.                 }
  58.                 if oldValue >= self.range.upperBound, self.bottomBounces && !self.watchOnlyDelta {
  59.                     delta = value - self.range.upperBound
  60.                 }
  61.                 if watchOnlyDelta && delta > 0 && oldValue < 0 {
  62.                     delta = value
  63.                 }
  64.                 if watchOnlyDelta && delta < 0 && oldValue > scrollContentSize.height - scrollViewSize.height {
  65.                     delta = value - (scrollContentSize.height - scrollViewSize.height)
  66.                 }
  67.                 if delta < 0 && self.current + delta < self.range.lowerBound && self.topBounces {
  68.                     delta = self.range.lowerBound - self.current
  69.                 }
  70.                 if delta > 0 && self.current + delta > self.range.upperBound && self.bottomBounces {
  71.                     delta = self.range.upperBound - self.current
  72.                 }
  73.                 self.current += delta
  74.                 if self.cancelsInRange {
  75.                     ScrollWatcher.stopRecursive = true
  76.                     scrollView.contentOffset.y -= delta
  77.                     ScrollWatcher.stopRecursive = false
  78.                 }
  79.             }
  80.            
  81.             let updatedValue = (self.current - self.range.lowerBound) / (self.range.upperBound - self.range.lowerBound)
  82.             if updatedValue != self.lastUpdateValue {
  83.                 self.lastUpdateValue = updatedValue
  84.                 self.update(updatedValue)
  85.             }
  86.         }
  87.     }
  88.    
  89.     deinit {
  90.         keyObservation.invalidate()
  91.     }
  92. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement