使用 RunLoop 监听屏幕滑动开始和停止的状态是一种更底层的实现方式。RunLoop 可以监听各种事件,包括触摸事件,从而可以检测到滑动的开始和停止。以下是一个示例代码,展示如何使用 RunLoop 来监听屏幕滑动开始和停止的事件,并使用 block 回调来通知外部:
#import <UIKit/UIKit.h>
typedef void (^ScrollStateBlock)(BOOL isStop);
@interface ScrollManager : NSObject
+ (instancetype)sharedManager;
- (void)startObservingWithView:(UIView *)view scrollStateBlock:(ScrollStateBlock)scrollStateBlock;
@end
@implementation ScrollManager {
CFRunLoopObserverRef _observer;
BOOL _isScrolling;
ScrollStateBlock _scrollStateBlock;
}
+ (instancetype)sharedManager {
static ScrollManager *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[self alloc] init];
});
return sharedManager;
}
- (void)startObservingWithView:(UIView *)view scrollStateBlock:(ScrollStateBlock)scrollStateBlock {
_scrollStateBlock = [scrollStateBlock copy];
CFRunLoopObserverContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &runLoopObserverCallback, &context);
CFRunLoopAddObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
}
void runLoopObserverCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
ScrollManager *manager = (__bridge ScrollManager *)info;
switch (activity) {
case kCFRunLoopBeforeWaiting:
if (manager->_isScrolling) {
manager->_isScrolling = NO;
if (manager->_scrollStateBlock) {
manager->_scrollStateBlock(YES);
}
}
break;
case kCFRunLoopAfterWaiting:
if (!manager->_isScrolling) {
manager->_isScrolling = YES;
if (manager->_scrollStateBlock) {
manager->_scrollStateBlock(NO);
}
}
break;
default:
break;
}
}
- (void)dealloc {
if (_observer) {
CFRunLoopRemoveObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
CFRelease(_observer);
_observer = NULL;
}
}
@end
使用示例
在你的视图控制器中,你可以这样使用 ScrollManager 类:
#import "ScrollManager.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 开始监听并设置回调 block
[[ScrollManager sharedManager] startObservingWithView:self.tableView scrollStateBlock:^(BOOL isStop) {
if (isStop) {
NSLog(@"Scroll stopped");
// 在这里处理滑动停止的事件,比喻在给Cell传显示数据时,停止再去刷新数据,减少不必要的Cell刷新
} else {
NSLog(@"Scroll started");
// 在这里处理滑动开始的事件
}
}];
}
@end
解释
-
ScrollManager 类:
- 使用
CFRunLoopObserverCreate创建一个 RunLoop 观察者,监听kCFRunLoopAllActivities活动。 - 在
runLoopObserverCallback回调函数中,根据 RunLoop 的活动状态(kCFRunLoopBeforeWaiting和kCFRunLoopAfterWaiting)来判断滑动开始和停止的状态。 - 使用
+sharedManager方法实现单例模式,确保只有一个实例。 - 提供
startObservingWithView:scrollStateBlock:方法来开始监听 RunLoop 活动,并通过 block 回调滑动状态。
- 使用
-
ViewController 类:
- 使用
[ScrollManager sharedManager]获取单例实例。 - 调用
startObservingWithView:scrollStateBlock:方法开始监听,并设置回调 block 来处理滑动开始和停止的事件。
- 使用
通过这种方式,你可以更简洁地监听和处理滑动状态,并且通过 block 回调一个 BOOL 值来表示滑动是否停止。