Created
June 6, 2018 02:54
-
-
Save GeekTree0101/497c91b2b29cdb912021e7b0d0e1c1f8 to your computer and use it in GitHub Desktop.
ASBatchFetching Customize for Bidirectional Fetching
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import AsyncDisplayKit | |
public protocol ChatNodeDelegate: ASCollectionDelegate { | |
func shouldAppendBatchFetch(for chatNode: ASCollectionNode) -> Bool | |
func shouldPrependBatchFetch(for chatNode: ASCollectionNode) -> Bool | |
func chatNode(_ chatNode: ASCollectionNode, | |
willBeginAppendBatchFetchWith context: ASBatchContext) | |
func chatNode(_ chatNode: ASCollectionNode, | |
willBeginPrependBatchFetchWith context: ASBatchContext) | |
} | |
class NodeController { .... } | |
// Update Pagination Status | |
extension NodeController { | |
open func completeBatchFetching(_ complated: Bool, endDirection: BatchFetchDirection) { | |
guard isPagingStatusEnable else { | |
print("[CAUTION] PagingStaute Disabled!") | |
return | |
} | |
switch endDirection { | |
case .append: | |
self.hasNextAppendItems = false | |
case .prepend: | |
self.hasNextPrependItem = false | |
default: | |
break | |
} | |
switch self.pagingStatus { | |
case .appending, .prepending: | |
self.pagingStatus = .some | |
default: break | |
} | |
self.batchFetchingContext.completeBatchFetching(complated) | |
} | |
} | |
// Batch Fetch Handling | |
extension NodeController: UIScrollViewDelegate { | |
open func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { } | |
open func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { } | |
public func scrollViewDidScroll(_ scrollView: UIScrollView) { | |
guard let chatDelegate = self.chatNode.delegate as? ChatNodeDelegate, ASInterfaceStateIncludesVisible(self.interfaceState) else { return } | |
self.chatNode.updateCurrentRange(with: .full) | |
self.beginChatNodeBatch(scrollView, chatDelegate: chatDelegate) | |
} | |
private func beginChatNodeBatch(_ scrollView: UIScrollView, | |
chatDelegate: ChatNodeDelegate) { | |
guard !self.pagingStatus.isLoading else { return } | |
if scrollView.isDragging, scrollView.isTracking { | |
return | |
} | |
let scrollVelocity = scrollView.panGestureRecognizer.velocity(in: super.view) | |
let scope = shouldFetchBatch(for: scrollView, | |
offset: scrollView.contentOffset.y, | |
scrollDirection: scrollDirection(scrollVelocity), | |
velocity: scrollVelocity) | |
switch scope { | |
case .append: | |
guard chatDelegate.shouldAppendBatchFetch(for: self.chatNode), | |
self.hasNextAppendItems else { | |
return | |
} | |
self.batchFetchingContext.beginBatchFetching() | |
if shouldPrintLog { | |
print("[DEBUG] Chat:\(Date().timeIntervalSinceReferenceDate) beging append fetching") | |
} | |
if isPagingStatusEnable { | |
self.pagingStatus = .appending | |
} | |
chatDelegate.chatNode(self.chatNode, willBeginAppendBatchFetchWith: self.batchFetchingContext) | |
case .prepend: | |
guard chatDelegate.shouldPrependBatchFetch(for: self.chatNode), | |
self.hasNextPrependItem else { | |
return | |
} | |
if shouldPrintLog { | |
print("[DEBUG] Chat:\(Date().timeIntervalSinceReferenceDate) beging prepend fetching") | |
} | |
self.batchFetchingContext.beginBatchFetching() | |
if isPagingStatusEnable { | |
self.pagingStatus = .prepending | |
} | |
chatDelegate.chatNode(self.chatNode, willBeginPrependBatchFetchWith: self.batchFetchingContext) | |
case .none: | |
break | |
} | |
} | |
private func scrollDirection(_ scrollVelocity: CGPoint) -> ASScrollDirection { | |
if scrollVelocity.y < 0.0 { | |
return .down | |
} else if scrollVelocity.y > 0.0 { | |
return .up | |
} else { | |
return ASScrollDirection(rawValue: 0) | |
} | |
} | |
private func shouldFetchBatch(for scrollView: UIScrollView, | |
offset: CGFloat, | |
scrollDirection: ASScrollDirection, | |
velocity: CGPoint) -> BatchFetchDirection { | |
guard !self.batchFetchingContext.isFetching(), scrollView.window != nil else { | |
return .none | |
} | |
let bounds: CGRect = scrollView.bounds | |
let leadingScreens: CGFloat = self.chatNode.leadingScreensForBatching | |
guard leadingScreens > 0.0, !bounds.isEmpty else { | |
return .none | |
} | |
let contentSize: CGSize = scrollView.contentSize | |
let viewLength = bounds.size.height | |
let contentLength = contentSize.height | |
// has small content | |
if contentLength < viewLength { | |
switch scrollDirection { | |
case .down: return .prepend | |
case .up: return .append | |
default: return .none | |
} | |
} | |
let triggerDistance = viewLength * leadingScreens | |
let remainingDistance = contentLength - viewLength - offset | |
switch scrollDirection { | |
case .down: | |
return remainingDistance <= triggerDistance ? .append: .none | |
case .up: | |
return offset < triggerDistance ? .prepend: .none | |
default: | |
return .none | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment