Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UIRefreshControl-like behavior #85

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 39 additions & 21 deletions PullToRefresh/PullToRefresh.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ open class PullToRefresh: NSObject {
fileprivate let animator: RefreshViewAnimator
fileprivate var isObserving = false

fileprivate var haveFinished = false

// MARK: - ScrollView & Observing

fileprivate var scrollViewDefaultInsets: UIEdgeInsets = .zero
Expand All @@ -77,9 +79,15 @@ open class PullToRefresh: NSObject {
didSet {
animator.animate(state)
switch state {
case .loading:
if oldValue != .loading {
animateLoadingState()
case .loading(let isDragging):
if oldValue != state {
if isDragging == false {
animateLoadingState()
if oldValue == .loading(isDragging: true) {
break//don't perform action twice
}
}
action?()
}

case .finished:
Expand Down Expand Up @@ -153,19 +161,26 @@ extension PullToRefresh {
}
}
let refreshViewHeight = refreshView.frame.size.height

switch offset {
case 0 where (state != .loading): state = .initial
case -refreshViewHeight...0 where (state != .loading && state != .finished):
state = .releasing(progress: -offset / refreshViewHeight)

case -1000...(-refreshViewHeight):
if state == .releasing(progress: 1) && scrollView?.isDragging == false {
state = .loading
} else if state != .loading && state != .finished {
state = .releasing(progress: 1)
if haveFinished && scrollView?.isDragging == false && (state == .loading(isDragging: false) || state == .loading(isDragging: true)) {
haveFinished = false
state = .finished
} else if state == .loading(isDragging: true) && scrollView?.isDragging == false {
state = .loading(isDragging: false)
} else {
switch offset {
case -5...0 where state != .loading(isDragging: false):
state = .initial
case -refreshViewHeight...0 where (state != .finished && state != .loading(isDragging: false) && state != .loading(isDragging: true)):
state = .releasing(progress: -offset / refreshViewHeight)

case -1000...(-refreshViewHeight):
if state == .releasing(progress: 1) {
state = .loading(isDragging: true)
} else if state != .finished && state != .loading(isDragging: false) && state != .loading(isDragging: true) {
state = .releasing(progress: 1)
}
default: break
}
default: break
}
} else if (context == &KVO.context && keyPath == KVO.ScrollViewPath.contentSize && object as? UIScrollView == scrollView) {
if case .bottom = position {
Expand Down Expand Up @@ -227,13 +242,18 @@ extension PullToRefresh {
scrollView?.setContentOffset(CGPoint(x: 0, y: offsetY), animated: true)
let delayTime = DispatchTime.now() + Double(Int64(0.27 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: delayTime) { [weak self] in
self?.state = .loading
self?.state = .loading(isDragging: false)
}
}

func endRefreshing() {
if state == .loading {
state = .finished
if state == .loading(isDragging: false) || state == .loading(isDragging: true) {
if scrollView?.isDragging == false {
state = .finished
haveFinished = false
} else {
haveFinished = true
}
}
}
}
Expand All @@ -255,7 +275,7 @@ private extension PullToRefresh {
case .top:
let insets = self.refreshView.frame.height + self.scrollViewDefaultInsets.top
scrollView.contentInset.top = insets
let offsetY = self.defaultInsets.top + self.refreshView.frame.height
let offsetY = self.scrollViewDefaultInsets.top + self.refreshView.frame.height
scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: -offsetY)

case .bottom:
Expand All @@ -270,8 +290,6 @@ private extension PullToRefresh {
}
}
)

action?()
}

func animateFinishedState() {
Expand Down
10 changes: 5 additions & 5 deletions PullToRefresh/State.swift
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ public enum State: Equatable, CustomStringConvertible {

case initial
case releasing(progress: CGFloat)
case loading
case loading(isDragging: Bool)
case finished

public var description: String {
switch self {
case .initial: return "Inital"
case .releasing(let progress): return "Releasing:\(progress)"
case .loading: return "Loading"
case .releasing(let progress): return "Releasing: \(progress)"
case .loading(let isDragging): return "Loading: \(isDragging)"
case .finished: return "Finished"
}
}
Expand All @@ -28,9 +28,9 @@ public enum State: Equatable, CustomStringConvertible {
public func ==(a: State, b: State) -> Bool {
switch (a, b) {
case (.initial, .initial): return true
case (.loading, .loading): return true
case (.finished, .finished): return true
case (.releasing, .releasing): return true
case (.loading(let isDragging1), .loading(let isDragging2)) where isDragging1 == isDragging2: return true
case (.releasing(let progress1), .releasing(let progress2)) where abs(progress1 - progress2) < 0.01: return true
default: return false
}
}
Expand Down
6 changes: 3 additions & 3 deletions PullToRefresh/UIScrollView+PullToRefresh.swift
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public extension UIScrollView {
sendSubview(toBack: view)
}

func removePullToRefresh(at position: Position) {
func removePullToRefresh(at position: Position = .top) {
switch position {
case .top:
topPullToRefresh?.refreshView.removeFromSuperview()
Expand All @@ -84,7 +84,7 @@ public extension UIScrollView {
removePullToRefresh(at: .bottom)
}

func startRefreshing(at position: Position) {
func startRefreshing(at position: Position = .top) {
switch position {
case .top:
topPullToRefresh?.startRefreshing()
Expand All @@ -94,7 +94,7 @@ public extension UIScrollView {
}
}

func endRefreshing(at position: Position) {
func endRefreshing(at position: Position = .top) {
switch position {
case .top:
topPullToRefresh?.endRefreshing()
Expand Down