UICollectionView快速点击cell无法高亮的原因

在 MTBCYAlbumKit 中有一个用于切换相册的 view,使用 collectionview 展示系统相册列表和用户相册列表,点击列表元素实现相册切换功能,其中 UI 要求点击时元素背景颜色变深,点击结束后恢复颜色。

collectionview 自身有两个代理方法可以实现此效果。

- (void)collectionView : (UICollectionView *)collectionView didHighlightItemAtIndexPath : (NSIndexPath *)indexPath
{
    [collectionView cellForItemAtIndexPath:indexPath].contentView.backgroundColor = HEXCOLOR(0xF5F5F5);
}

- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath : (NSIndexPath *)indexPath
{
    [collectionView cellForItemAtIndexPath:indexPath].contentView.backgroundColor = IMERCHANT_WHITE;
}

但是在使用中发现有如下问题:快速点击列表内元素时不会出现高亮效果,只有按住一小段时间才会出现高亮效果。网上给出的解决方法是将 collectionview 的 delaysContentTouches 属性设置为 NO,下面阐述调研后的具体原因。

delaysContentTouches 属性

delaysContentTouches 其实是 UIScrollView 的属性,它的含义如下

A Boolean value that determines whether the scroll view delays the handling of touch-down gestures.

一个布尔值,用于确定滚动视图是否延迟触摸手势的处理。

这里涉及到 UIScrollView 对于手势的处理逻辑,当手指开始 touch 屏幕时,scrollview 会启动一个短时间的定时器,在此期间,如果检测到手势有明显滑动,则 scrollView 发生滚动,并且不会将事件下发到 cell。如果此期间没有明显滑动,则触发 cell 的 touchBegin 事件,但同时如果之后手指发生滑动了,scrollView 就会传递 touchCancelled 事件给 cell。

而如果将默认值为 YES 的 delaysContentTouches 属性设置为 NO,则不会启动此定时器,直接触发 cell 的 touchBegin 事件。

高亮效果

但是高亮效果是由 UICollectionView 确定的,为什么不设置 delaysContentTouches 为 NO 就不能出现高亮效果呢。

我对 UICollectionView 一些关键的代理方法做了埋点打印处理,具体如下

- (void)collectionView : (UICollectionView *)collectionView didHighlightItemAtIndexPath : (NSIndexPath *)indexPath
{
    NSLog(@"didHighlight");
    [collectionView cellForItemAtIndexPath:indexPath].contentView.backgroundColor = HEXCOLOR(0xF5F5F5);
}

- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath : (NSIndexPath *)indexPath
{
    NSLog(@"didUnHighlight");
    [collectionView cellForItemAtIndexPath:indexPath].contentView.backgroundColor = IMERCHANT_WHITE;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"didSelectItemAtIndexPath");
    ···
}

同时对 cell 的手势处理方法进行了覆写

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    NSLog(@"touchesBegan");
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesEnded1");
    [super touchesEnded:touches withEvent:event];
    NSLog(@"touchesEnded2");
}

分别对 delaysContentTouches 为 NO 和 YES 的情况进行五次点击测试后,得出如下数据

  • delaysContentTouches = NO,快速点击变色
2018-02-28 09:12:39.942214+0800 MTBCYAlbumKit[22929:9571394] didHighlight
2018-02-28 09:12:39.942469+0800 MTBCYAlbumKit[22929:9571394] touchesBegan
2018-02-28 09:12:39.986804+0800 MTBCYAlbumKit[22929:9571394] touchesEnded1
2018-02-28 09:12:39.987212+0800 MTBCYAlbumKit[22929:9571394] didUnHighlight
2018-02-28 09:12:39.987573+0800 MTBCYAlbumKit[22929:9571394] didSelectItemAtIndexPath
2018-02-28 09:12:39.987737+0800 MTBCYAlbumKit[22929:9571394] touchesEnded2


2018-02-28 09:17:48.398848+0800 MTBCYAlbumKit[22936:9574330] didHighlight
2018-02-28 09:17:48.399059+0800 MTBCYAlbumKit[22936:9574330] touchesBegan
2018-02-28 09:17:48.443024+0800 MTBCYAlbumKit[22936:9574330] touchesEnded1
2018-02-28 09:17:48.443397+0800 MTBCYAlbumKit[22936:9574330] didUnHighlight
2018-02-28 09:17:48.443793+0800 MTBCYAlbumKit[22936:9574330] didSelectItemAtIndexPath
2018-02-28 09:17:48.444018+0800 MTBCYAlbumKit[22936:9574330] touchesEnded2

2018-02-28 09:17:57.665995+0800 MTBCYAlbumKit[22936:9574330] didHighlight
2018-02-28 09:17:57.666365+0800 MTBCYAlbumKit[22936:9574330] touchesBegan
2018-02-28 09:17:57.727243+0800 MTBCYAlbumKit[22936:9574330] touchesEnded1
2018-02-28 09:17:57.727588+0800 MTBCYAlbumKit[22936:9574330] didUnHighlight
2018-02-28 09:17:57.727932+0800 MTBCYAlbumKit[22936:9574330] didSelectItemAtIndexPath
2018-02-28 09:17:57.728064+0800 MTBCYAlbumKit[22936:9574330] touchesEnded2

2018-02-28 09:18:08.884289+0800 MTBCYAlbumKit[22936:9574330] didHighlight
2018-02-28 09:18:08.884659+0800 MTBCYAlbumKit[22936:9574330] touchesBegan
2018-02-28 09:18:08.945185+0800 MTBCYAlbumKit[22936:9574330] touchesEnded1
2018-02-28 09:18:08.945578+0800 MTBCYAlbumKit[22936:9574330] didUnHighlight
2018-02-28 09:18:08.946008+0800 MTBCYAlbumKit[22936:9574330] didSelectItemAtIndexPath
2018-02-28 09:18:08.946153+0800 MTBCYAlbumKit[22936:9574330] touchesEnded2

2018-02-28 09:18:28.736691+0800 MTBCYAlbumKit[22936:9574330] didHighlight
2018-02-28 09:18:28.737061+0800 MTBCYAlbumKit[22936:9574330] touchesBegan
2018-02-28 09:18:28.781248+0800 MTBCYAlbumKit[22936:9574330] touchesEnded1
2018-02-28 09:18:28.781590+0800 MTBCYAlbumKit[22936:9574330] didUnHighlight
2018-02-28 09:18:28.782002+0800 MTBCYAlbumKit[22936:9574330] didSelectItemAtIndexPath
2018-02-28 09:18:28.782147+0800 MTBCYAlbumKit[22936:9574330] touchesEnded2
  • delaysContentTouches = YES,快速点击不变色
2018-02-28 09:13:25.126845+0800 MTBCYAlbumKit[22932:9572093] didHighlight
2018-02-28 09:13:25.127143+0800 MTBCYAlbumKit[22932:9572093] touchesBegan
2018-02-28 09:13:25.127362+0800 MTBCYAlbumKit[22932:9572093] touchesEnded1
2018-02-28 09:13:25.127587+0800 MTBCYAlbumKit[22932:9572093] didUnHighlight
2018-02-28 09:13:25.127891+0800 MTBCYAlbumKit[22932:9572093] didSelectItemAtIndexPath
2018-02-28 09:13:25.128023+0800 MTBCYAlbumKit[22932:9572093] touchesEnded2

2018-02-28 09:15:33.459640+0800 MTBCYAlbumKit[22932:9572093] didHighlight
2018-02-28 09:15:33.459983+0800 MTBCYAlbumKit[22932:9572093] touchesBegan
2018-02-28 09:15:33.460154+0800 MTBCYAlbumKit[22932:9572093] touchesEnded1
2018-02-28 09:15:33.460321+0800 MTBCYAlbumKit[22932:9572093] didUnHighlight
2018-02-28 09:15:33.460587+0800 MTBCYAlbumKit[22932:9572093] didSelectItemAtIndexPath
2018-02-28 09:15:33.460714+0800 MTBCYAlbumKit[22932:9572093] touchesEnded2

2018-02-28 09:16:33.733329+0800 MTBCYAlbumKit[22932:9572093] didHighlight
2018-02-28 09:16:33.733524+0800 MTBCYAlbumKit[22932:9572093] touchesBegan
2018-02-28 09:16:33.733674+0800 MTBCYAlbumKit[22932:9572093] touchesEnded1
2018-02-28 09:16:33.733760+0800 MTBCYAlbumKit[22932:9572093] didUnHighlight
2018-02-28 09:16:33.733864+0800 MTBCYAlbumKit[22932:9572093] didSelectItemAtIndexPath
2018-02-28 09:16:33.733975+0800 MTBCYAlbumKit[22932:9572093] touchesEnded2

2018-02-28 09:17:01.455392+0800 MTBCYAlbumKit[22932:9572093] didHighlight
2018-02-28 09:17:01.455700+0800 MTBCYAlbumKit[22932:9572093] touchesBegan
2018-02-28 09:17:01.455874+0800 MTBCYAlbumKit[22932:9572093] touchesEnded1
2018-02-28 09:17:01.456044+0800 MTBCYAlbumKit[22932:9572093] didUnHighlight
2018-02-28 09:17:01.456308+0800 MTBCYAlbumKit[22932:9572093] didSelectItemAtIndexPath
2018-02-28 09:17:01.456486+0800 MTBCYAlbumKit[22932:9572093] touchesEnded2

2018-02-28 09:17:14.455519+0800 MTBCYAlbumKit[22932:9572093] didHighlight
2018-02-28 09:17:14.455864+0800 MTBCYAlbumKit[22932:9572093] touchesBegan
2018-02-28 09:17:14.456056+0800 MTBCYAlbumKit[22932:9572093] touchesEnded1
2018-02-28 09:17:14.456232+0800 MTBCYAlbumKit[22932:9572093] didUnHighlight
2018-02-28 09:17:14.456488+0800 MTBCYAlbumKit[22932:9572093] didSelectItemAtIndexPath
2018-02-28 09:17:14.456613+0800 MTBCYAlbumKit[22932:9572093] touchesEnded2

最终统计 didHighlight 和 didUnHighlight 之间的时间间隔,得到数据如下,时间单位为秒。

序号 delaysContentTouches = NO delaysContentTouches = YES
1 0.044998 0.000742
2 0.044935 0.000681
3 0.061593 0.000431
4 0.061289 0.000652
5 0.044899 0.000713
平均值 0.0515428 0.0006438

可以看出当 delaysContentTouches = YES 时,highlight 和 unhighlight 之间间隔比 delaysContentTouches = NO 时小了两个数量级,所以推测出 delaysContentTouches = YES 时不变色的 可能原因 是变色过快,不能被肉眼察觉。另外值得注意的是,大量耗时过程发生在 touchesBegan 与 touchesEnd 之间。

进一步对 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 方法进行埋点打印,多次测试后发现如下数据

  • delaysContentTouches = YES 时不会触发 touchesMoved 事件
  • delaysContentTouches = NO 时可能触发 touchesMoved 事件
delaysContentTouches = NO

2018-02-28 09:39:33.278930+0800 MTBCYAlbumKit[22948:9583284] didHighlight
2018-02-28 09:39:33.279310+0800 MTBCYAlbumKit[22948:9583284] touchesBegan
2018-02-28 09:39:33.292573+0800 MTBCYAlbumKit[22948:9583284] touchMoved
2018-02-28 09:39:33.308281+0800 MTBCYAlbumKit[22948:9583284] touchMoved
2018-02-28 09:39:33.340444+0800 MTBCYAlbumKit[22948:9583284] touchesEnded1
2018-02-28 09:39:33.340753+0800 MTBCYAlbumKit[22948:9583284] didUnHighlight
2018-02-28 09:39:33.341192+0800 MTBCYAlbumKit[22948:9583284] didSelectItemAtIndexPath
2018-02-28 09:39:33.341400+0800 MTBCYAlbumKit[22948:9583284] touchesEnded2

delaysContentTouches = YES

2018-02-28 09:37:12.255610+0800 MTBCYAlbumKit[22945:9582286] didHighlight
2018-02-28 09:37:12.255807+0800 MTBCYAlbumKit[22945:9582286] touchesBegan
2018-02-28 09:37:12.256025+0800 MTBCYAlbumKit[22945:9582286] touchesEnded1
2018-02-28 09:37:12.256137+0800 MTBCYAlbumKit[22945:9582286] didUnHighlight
2018-02-28 09:37:12.256255+0800 MTBCYAlbumKit[22945:9582286] didSelectItemAtIndexPath
2018-02-28 09:37:12.256366+0800 MTBCYAlbumKit[22945:9582286] touchesEnded2

所以 delaysContentTouches = NO 时大部分间隔发生在 touchBegin 和 touchEnd 之间,推测 可能原因 是 cell 进行 touchesMoved 检测导致的时间消耗。

而网上对于实现 collectionView 点击高亮的补充说明通常如下

然而如果你实现了 本文介绍的 这个两个方法改变选中颜色,你会发现只有长按时才会看到设置的颜色。

原因:长按没有松手的时候,触发的是高亮方法,松手触发的是取消高亮的方法。轻触点击的时候会很快速的响应 高亮和取消高亮的方法,所以看不到颜色的改变。此时,需要设置delaysContentTouches属性为NO,此时当点击的时候会立刻调用点击事件的begin方法,率先变成高亮状态。

其实真正耗时的操作并不是 begin 之前,而是在 begin 之后,end 之前。

canCancelContentTouches

与 delaysContentTouches 相关的属性还有一个 canCancelContentTouches 属性,它的含义如下

A Boolean value that controls whether touches in the content view always lead to tracking.

If the value of this property is YES and a view in the content has begun tracking a finger touching it, and if the user drags the finger enough to initiate a scroll, the view receives a touchesCancelled:withEvent: message and the scroll view handles the touch as a scroll. If the value of this property is NO, the scroll view does not scroll regardless of finger movement once the content view starts tracking.

也就是可以控制当一个子控件开始跟踪触摸事件后,能否接收 touchesCancelled 事件从而取消事件处理过程。

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

推荐阅读更多精彩内容