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

前言

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


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的一些小心得

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心得

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容