RuntimePlayer-获取并控制UIScrollView的滑动手势

以后每用Runtime解决一个问题,就会记录在这个文集里。

我将以真实的使用场景为大家讲述Runtime的各种用法,让Runtime真正的投入到生产中。

合辑demo Github地址

正文

当我们需要在ScrollView滑动到一定位置的时候屏蔽滑动并做一些其他和滑动有关的事时,UIScrollViewDelegate提供的几个方法显得弱不禁风。可以继承ScrollView并重写一些方法实现相应需求。直到,这个页面换成了WebView。

WebView是个比较尴尬的控件。不管是UIWebView还是WKWebView都不直接继承UIScrollView,而是用组合的方式持有了一个UIScrollView,这就让对其滑动的控制如履薄冰,困难重重。

之前遇见过一个需求,希望滑动webView到contentOffset.y等于0的时候开始改变Frame。scroll套scroll的方案最初就放弃了,也想过自定义Pan手势,但明显会造成webView本身滑动出现问题。也考虑过KVOcontentOffset,但效果差强人意。

于是只能考虑非常规实现。

直觉上,我需要在正确的时间拿到ScrollView的pan手势,问题就基本解决了。

经过一段时间的调试,我发现,UIScrollView有一个handlePan:的方法用来响应滑动pan手势。于是钩了这个方法,由外部来判断当前的这一次change,是要交给ScrollView,还是做其他处理。

写了个协议大概是这样

@protocol ScrollActionTransfer 

- (void)scrollView:(UIScrollView *)scrollView transferPanAction:(UIPanGestureRecognizer *)gesture;

- (BOOL)scrollView:(UIScrollView *)scrollView useSystemPanAction:(UIPanGestureRecognizer *)gesture;

@end

实现的话是这样

@implementation UIScrollView (ScrollActionTransfer)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method m1 = class_getInstanceMethod([self class],NSSelectorFromString(@"wel_panAction:"));
        Method m2 = class_getInstanceMethod([self class], NSSelectorFromString(@"handlePan:"));
        method_exchangeImplementations(m1,m2);
    });
}

- (void)setScrollActionDelegate:(id)scrollActionDelegate {
    objc_setAssociatedObject(self, @selector(scrollActionDelegate), scrollActionDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id )scrollActionDelegate {
    return objc_getAssociatedObject(self, _cmd);
}

- (void)wel_panAction:(UIPanGestureRecognizer *)gesture {
    
    if(self.scrollActionDelegate) {
        
        if([self.scrollActionDelegate scrollView:self useSystemPanAction:gesture]) {
            [self wel_panAction:gesture];
        } else {
            [self.scrollActionDelegate scrollView:self transferPanAction:gesture];
        }
    } else {
        [self wel_panAction:gesture];
    }
}
@end

有了这个小东西,就可以轻松的实现上述需求。

当然,这里还是有一个需要注意的问题,handlePan:并不是说可以接受任意的pan手势。经测试这个手势你可以拿出来用传给其他的控件,但是你不能自己new一个pan手势往里面传。也就是说,apple天气那样的界面,开始于scroll的手势,可以传给View,而开始于view的手势则无法传给Scroll。实现类似界面的还是得用KVO+contentInset来实现。

你可能感兴趣的:(RuntimePlayer-获取并控制UIScrollView的滑动手势)