Skip to content

Instantly share code, notes, and snippets.

@GeekTree0101
Created June 6, 2018 02:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save GeekTree0101/497c91b2b29cdb912021e7b0d0e1c1f8 to your computer and use it in GitHub Desktop.
Save GeekTree0101/497c91b2b29cdb912021e7b0d0e1c1f8 to your computer and use it in GitHub Desktop.
ASBatchFetching Customize for Bidirectional Fetching
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