// // HistoryPreloader.m // AIIM // // Created by qitewei on 2025/5/20. // #import "HistoryPreloader.h" #import @interface HistoryPreloader() { CADisplayLink *_displayLink; CGFloat _initialOffset; BOOL _isUserInitiatedScroll; NSTimeInterval _lastTriggerTime; CGFloat _lastScrollVelocity; } @end @implementation HistoryPreloader - (instancetype)init { self = [super init]; if (self) { _threshold = 300.0; // 默认阈值 _initialOffset = CGFLOAT_MAX; } return self; } - (void)dealloc { [self stopMonitoring]; } #pragma mark - 公共方法 - (void)startMonitoring { if (_displayLink) return; // 记录初始偏移量(考虑contentInset) _initialOffset = -self.tableView.contentInset.top; _isUserInitiatedScroll = NO; // 设置DisplayLink监控滚动 _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleScrollCheck)]; [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; } - (void)stopMonitoring { [_displayLink invalidate]; _displayLink = nil; } - (void)resetScrollState { _isUserInitiatedScroll = NO; _initialOffset = -self.tableView.contentInset.top; } #pragma mark - 私有方法 - (void)handleScrollCheck { CGFloat currentOffset = self.tableView.contentOffset.y; // 1. 检测是否是用户发起的滑动 if (!_isUserInitiatedScroll) { // 使用5pt的阈值避免误判 if (fabs(currentOffset - _initialOffset) > 5.0) { _isUserInitiatedScroll = YES; } else { return; // 未滑动,直接返回 } } // 2. 计算滚动速度(用于动态调整阈值) CFTimeInterval timestamp = _displayLink.timestamp; static CFTimeInterval lastTimestamp = 0; if (lastTimestamp != 0) { _lastScrollVelocity = (currentOffset - _lastScrollVelocity) / (timestamp - lastTimestamp); } lastTimestamp = timestamp; _lastScrollVelocity = currentOffset; // 3. 动态调整阈值(可选) CGFloat dynamicThreshold = [self dynamicThresholdBasedOnVelocity:_lastScrollVelocity]; // 4. 检查是否需要触发预加载 if (currentOffset < dynamicThreshold) { [self tryTriggerPreload]; } } - (CGFloat)dynamicThresholdBasedOnVelocity:(CGFloat)velocity { // 基础阈值 CGFloat baseThreshold = self.threshold; // 根据滚动速度调整(速度越快,阈值越大,提前触发) if (fabs(velocity) > 100) { // 快速滚动 return baseThreshold * 1.5; } else if (fabs(velocity) < 20) { // 慢速滚动 return baseThreshold * 0.8; } return baseThreshold; } - (void)tryTriggerPreload { // 冷却时间检查(至少间隔1秒) NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; if (now - _lastTriggerTime < 1.0){ // 触发过快加载加载回调 if (self.toofast) { self.toofast(); } return; } _lastTriggerTime = now; // 触发加载回调 if (self.loadBlock) { self.loadBlock(); } // 短暂停止监控防止连续触发 [self stopMonitoring]; __weak typeof(self) weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [weakSelf startMonitoring]; }); } #pragma mark - 只读属性访问 - (BOOL)isUserInitiatedScroll { return _isUserInitiatedScroll; } @end