响应链 --- 被很多人忽视的另一种数据交互方式

前言

这篇文章有些是借鉴了其他博客文章的知识点加以理解的,在最下方我会列出参考的链接。有兴趣的可以点进去看下。

主要内容

本篇文章的主要内容有响应链的构成、响应链的传递过程、hit:test判定流程、通过响应链进行交互传递。

1.响应链的构成

从名字中开始理解,响应链是由一系列响应者通过某种联系构成的链条。

  • 响应者:具有响应和处理事件能力的对象。基类是UIResponder=

  • 链条连接器:pointInside 和hit:test方法

  • 响应者类关系图


    响应者类关系图.png

2.响应链的传递

当界面上的一个button被点击时
  • 1.系统会封装一个UIEvent对象传递到Appdelegate
  • 2.由Appdelegate向Application、UIWindow等向上传递事件
  • 3.视图收到父响应者传递的事件后,通过hitView判断是否选中
  • 4.如果没有判定中,那么不处理,如果判定中,遍历子视图,递归执行3和4
  • 5.最后递归找到最顶层的button,最适合的视图
  • 6.如果能响应,执行它的交互响应 ,不能的话,递归到上一个响应者,执行响应 。
  • 7.如果一直递归到appdelegate到都没响应,则废弃

不能响应的原因 :

  • view.hidden = YES
  • view.alpha<0.01
  • view.userinterface = NO
  • 不添加交互事件并不是不能响应,只是默认不做处理
响应链层级
传递图

3.hit:test流程

刚才我们说到响应者需要将事件在响应链上传递,在内部是通过两个方法进行传递 pointinside 和hit test

1.首先对响应链最底层的View(UIWindow)视图进行命中判定,调用hittest:withevent方法
2.如果判定不是该视图,则返回nil,pointInside:withevent方法无效,如果命中,则根据pointInside, 返回是不是响应区域,如果是,则遍历该视图的子视图进行hittest判定
3.重复2,知道找到最上层最合适的视图,然后执行事件

这张图是盗的
假设用户点击了视图E

1.首先touch会命中window,查出上级视图是viewA
2.viewA判定在A中,然后向上遍历子视图B和C
3.B判定不在自己的视图内,返回nil,B分支结束
4.C判定在自己的视图内,向上遍历D和E进行判定
5.D判定不在视图内,D分支结束
6.E判定在该视图内,子视图为nil,则E是最合适视图

  1. E进行响应,如果E无法响应,则执行父视图C的响应

以上就是响应链传递的流程,说完了流程现在来说说响应链具体有何应用

应用一: 超区或者裁区响应
image.png

对于这张图片,一般简单做法就是方形视图切圆角,这样的话圆形周边的四个角(红色区域)也会响应,如果交互或者产品要求只能圆形响应的话,这时候就需要重写方法

#import "EDHSqurView.h"

@implementation EDHSqurView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    NSLog(@"%s",__func__);
    UIView *vuew = [super hitTest:point withEvent:event];
    return vuew;
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    NSLog(@"%s",__func__);
    //已经知道是个正方形
    CGFloat radius = self.frame.size.width/2;
   
    UIBezierPath *bezier = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius, radius)
                                                          radius:radius
                                                      startAngle:0 endAngle:M_PI*2
                                                       clockwise:1];
    return CGPathContainsPoint(bezier.CGPath, NULL, point, NO);
    
}

@end

这段代码要用到的是下面那个方法,进行裁剪交互区域,返回可交互的圆形区域

按钮超区.png

这段图片也是进行超区处理

应用二:通过响应链进行对象间交互
目前常用的数据/事件回传有block、delegate、notification,各有所长。响应链具有逐层传递的特点,可通过nextresponder取到下一个响应者,基于这个特点,可以设计通过链路进行对象的数据回传

具体做法

  • 1.通过UIResponder的一个category,定义一个方法,通过响应链向底层传递
  • 2.通过extern nsstring const 方式定义交互事件的eventname名字(也可以硬编码)
  • 3.以tableview为例,cell上有多个交互事件,在button的点击事件里调用category方法
  • 4.在controller里面接收到上一层响应者发来的信息,处理,若需要继续传递(或穿透传递) 则调用category的方法


    1-定义分类

    2-定义eventname

    3-在交互事件是执行category

    4-在控制器里的操作
下层响应者接受多个响应事件的strategy模式

当下层响应者例如controller接受来自多个子视图的事件时,会导致判断的if else冗余,这时可以采用strategy对每个eventname分类处理

解决办法:定义一个字典,eventname做key,invocation做value
在routeEvent里面通过eventname取出strategy字典的value - invocation,
然后[invocation invoke]

这种方式要求每个eventname都对应一个selector,如果event不是很多的话,
用if else 也没什么关系
如下图


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

推荐阅读更多精彩内容

  • 好奇触摸事件是如何从屏幕转移到APP内的?困惑于Cell怎么突然不能点击了?纠结于如何实现这个奇葩响应需求?亦或是...
    Lotheve阅读 56,585评论 51 597
  • 在iOS开发中经常会涉及到触摸事件。本想自己总结一下,但是遇到了这篇文章,感觉总结的已经很到位,特此转载。作者:L...
    WQ_UESTC阅读 5,987评论 4 26
  • 事件传递:响应者链 当你设计一个app的时候,你很可能需要你的app能够动态响应某些事件。比如,触摸可以发生在屏幕...
    hjfrun阅读 1,017评论 1 5
  • 用户以多种方式操纵他们的iOS设备,例如触摸屏幕或摇动设备。 iOS会解释用户何时以及如何操作硬件并将此信息传递到...
    坤坤同学阅读 3,975评论 7 19
  • 在开发过程中,大家或多或少的都会碰到令人头疼的手势冲突问题,正好前两天碰到一个类似的bug,于是借着这个机会了解了...
    闫仕伟阅读 5,294评论 2 23