iOS开发,UISlider滑块不灵敏问题以及在UIScrollView上添加Slider造成手势冲突问题心得

前言

最近在做项目时候有如下这样一个界面


iOS开发,UISlider滑块不灵敏问题以及在UIScrollView上添加Slider造成手势冲突问题心得_第1张图片
1.png

这个页面涉及到视频播放拖动进度条的需求,测试那边提过来的bug是进度条滑块不够灵敏,交互的时候很难响应用户的操作.苦逼码农一枚,提了bug就得改啊.

正文

在网上看了很多关于这方面的处理,总结了下大致3种方法

  • 一种是直接改变滑块图片的大小.但是在项目中有时为了整体风格的统一和样式匹配.不方便修改图片大小.所以个人不是很喜欢这个解决方法.
  • 第二种,是继承UISlider重写如下方法,细微的扩展一下滑块的响应范围
背景:由于UI给的thumbImage图片过小,默认UISlider开始拖动的手势范围只有thumbImage的大小之内.为了解决这个问题需要创建一个子类继承于UISlider.重写其中的方法:
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value
{
//y轴方向改变手势范围
    rect.origin.y = rect.origin.y - 10;
    rect.size.height = rect.size.height + 20;
    return CGRectInset ([super thumbRectForBounds:bounds trackRect:rect value:value], 10 ,10);
}
将会增加Y轴方向thumbImage的触控范围

这个修改的偏移数值,我还没有做深入研究,好像改太大了的话,滑块会消失.我打印了下bounds和rect好像相差的就是10.所以估计这里的偏移数值不是随便给的,最好不要随便改.

这个方法,我试了一下,效果有,但是不明显,需求不高的情况下可以就用这个方法

*第三种方法,我认为是效果最好的,需要继承UISlider重写如下方法

#define SLIDER_X_BOUND 30
#define SLIDER_Y_BOUND 40

- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value;
{

    rect.origin.x = rect.origin.x;
    rect.size.width = rect.size.width;
    CGRect result = [super thumbRectForBounds:bounds trackRect:rect value:value];
//记录下最终的frame
    lastBounds = result;
    return result;
}
//检查点击事件点击范围是否能够交给self处理
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//调用父类方法,找到能够处理event的view
    UIView* result = [super hitTest:point withEvent:event];
    if (result != self) {
        /*如果这个view不是self,我们给slider扩充一下响应范围,
          这里的扩充范围数据就可以自己设置了
        */
        if ((point.y >= -15) &&
            (point.y < (lastBounds.size.height + SLIDER_Y_BOUND)) &&
            (point.x >= 0 && point.x < CGRectGetWidth(self.bounds))) {
            //如果在扩充的范围类,就将event的处理权交给self
            result = self;
        }
    }
    //否则,返回能够处理的view
    return result;
}
//检查是点击事件的点是否在slider范围内
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    //调用父类判断
    BOOL result = [super pointInside:point withEvent:event];
    
    if (!result) {
        //同理,如果不在slider范围类,扩充响应范围
        if ((point.x >= (lastBounds.origin.x - SLIDER_X_BOUND)) && (point.x <= (lastBounds.origin.x + lastBounds.size.width + SLIDER_X_BOUND))
            && (point.y >= -SLIDER_Y_BOUND) && (point.y < (lastBounds.size.height + SLIDER_Y_BOUND))) {
            //在扩充范围内,返回yes
            result = YES;
        }
    }
    
    //NSLog(@"UISlider(%d).pointInside: (%f, %f) result=%d", self, point.x, point.y, result);
    //否则返回父类的结果
    return result;
}

对以上重写方法有疑问的,或则不是很了解的,请移驾该篇文章事件处理,响应者链条

通过上文的方法,基本就可以解决滑块不灵敏的问题了而且效果不错.当然重写方法不一定非要这么写不可,可以根据项目需求和每个人的理解以及技术水准不一样.标准不是唯一的.

看似问题解决了,我终于可以告诉测试我的bug解决了.然而天不遂人愿.在测试demo上一切no problem.但当我运用到项目中问题出现了.滑块给人的感觉还是不是很灵敏.不能直接用手指触碰到滑块立马滑动,必须要按住一会才能很好的滑动.

这个问题困扰好久,最后感谢这篇文章关于ScrollerView的一些小心得

iOS开发,UISlider滑块不灵敏问题以及在UIScrollView上添加Slider造成手势冲突问题心得_第2张图片
2.png

这个界面顶部有一行tab导航条,所以这个界面是需要支持左右滑动切换tab导航条的.这个功能当然是基于scrollView做的,追根究底.还是事件响应处理的问题

UIScrollerView中添加了一个UISlider的组件,在手势滑动的过程中,很难滑动到UISlider这个控件,经常是滑动的时候UIScrollerView进行了滚动,

而UISlider这个控件没有滑动,让人很抓狂。

下面引用一下前辈的总结,因为自己觉得没有他总结的详细

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

总结以上所述,总算略有眉目.于是我为这个界面写了一个UIScrollView的类扩展重写了方法:

看来是UIScrollView的问题。直接拖动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;
}

OK,cmd + R运行项目,大功告成!!!

写在最后

参考:
iOS UISlider滑动块触摸范围调整变大
关于UISlider的拖动手势不灵敏的解决方法
UIScorllView心得

你可能感兴趣的:(iOS开发,UISlider滑块不灵敏问题以及在UIScrollView上添加Slider造成手势冲突问题心得)