【技巧】UIScrollerView中的UISlider优先响应

版权声明:未经博主同意不得转载 https://blog.csdn.net/bluefish89/article/details/82713698

一、背景:

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

二、分析

网上说的通过重载UISlider的
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value方法,改变滑块的响应区域,其实并没什么卵用。
真正的问题还是出在了event响应上。

我们从先探究UIScrollView的工作原理:
UIScrollView有一个BOOL类型的tracking属性,用来返回用户是否已经触及内容并打算开始滚动,
当手指触摸到UIScrollView内容的一瞬间,会产生下面的动作:

  1. 列表内容
  2. 拦截触摸事件,tracking属性变为YES
  3. 一个内置的计时器开始生效,用来监控在极短的事件间隔内是否发生了手指移动

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;
}

猜你喜欢

转载自blog.csdn.net/bluefish89/article/details/82713698
今日推荐