UIScrollerView中的UISlider优先响应

一、背景:

在项目开发时遇到一个问题,我在UIScrollerView中添加了一个UISlider的组件,在手势滑动的过程中,很难滑动到UISlider这个控件,经常是滑动的时候UIScrollerView进行了滚动,而UISlider这个控件没有滑动,让人很抓狂。

二、分析

网上说的通过重载UISlider的

- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value方法,改变滑块的响应区域,其实并没什么卵用。

真正的问题还是出在了event响应上。

我们从先探究UIScrollView的工作原理:

UIScrollView有一个BOOL类型的tracking属性,用来返回用户是否已经触及内容并打算开始滚动,

当手指触摸到UIScrollView内容的一瞬间,会产生下面的动作:

列表内容

拦截触摸事件,tracking属性变为YES

一个内置的计时器开始生效,用来监控在极短的事件间隔内是否发生了手指移动

case1:当检测到时间间隔内手指发生了移动,UIScrollView自己触发滚动,tracking属性变为NO,手指触摸下即使有(可以响应触摸事件的)内部控件也不会再响应触摸事件。

case2:当检测到时间间隔内手指没有移动,tracking属性保持YES,手指触摸下如果有(可以响应触摸事件的)内部控件,则将触摸事件传递给控件进行处理。

总结:当手指touch的时候,UIScrollView会拦截所有event,然后等待150ms,在这段时间内,如果没有手指没有移动,当时间结束时,UIScrollView会发送tracking event到子视图上,并且自身不滑动。在时间结束前,手指发生了移动,那么UIScrollView就会进行滑动,从而取消发送tracking。

对于我们现在的情况,就是

直接拖动UISlider,此时touch时间在150ms以内,UIScrollView会认为是拖动自己,从而拦截了event,导致UISlider接受不到滑动的event。但是只要按住UISlider一会再拖动,此时touch时间超过150ms,因此滑动的event会发送到UISlider上

三、解决

重写UIScrollView的hitTest方法:当滑动UISlider时,使UIScrollView不可滑动

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    /*

    直接拖动UISlider,此时touch时间在150ms以内,UIScrollView会认为是拖动自己,从而拦截了event,导致UISlider接受不到滑动的event。但是只要按住UISlider一会再拖动,此时此时touch时间超过150ms,因此滑动的event会发送到UISlider上。

    */

    UIView *view = [super hitTest:point withEvent:event];

    if([view isKindOfClass:[UISlider class]]) {

        //如果响应view是UISlider,则scrollview禁止滑动

        self.scrollEnabled = NO;

    } else {  //如果不是,则恢复滑动

        self.scrollEnabled = YES;

    }

    return view;

}

你可能感兴趣的:(UIScrollerView中的UISlider优先响应)