響應(yīng)鏈 --- 被很多人忽視的另一種數(shù)據(jù)交互方式

前言

這篇文章有些是借鑒了其他博客文章的知識(shí)點(diǎn)加以理解的,在最下方我會(huì)列出參考的鏈接。有興趣的可以點(diǎn)進(jìn)去看下。

主要內(nèi)容

本篇文章的主要內(nèi)容有響應(yīng)鏈的構(gòu)成、響應(yīng)鏈的傳遞過程、hit:test判定流程、通過響應(yīng)鏈進(jìn)行交互傳遞。

1.響應(yīng)鏈的構(gòu)成

從名字中開始理解,響應(yīng)鏈?zhǔn)怯梢幌盗许憫?yīng)者通過某種聯(lián)系構(gòu)成的鏈條。

  • 響應(yīng)者:具有響應(yīng)和處理事件能力的對(duì)象?;愂荱IResponder=

  • 鏈條連接器:pointInside 和hit:test方法

  • 響應(yīng)者類關(guān)系圖


    響應(yīng)者類關(guān)系圖.png

2.響應(yīng)鏈的傳遞

當(dāng)界面上的一個(gè)button被點(diǎn)擊時(shí)
  • 1.系統(tǒng)會(huì)封裝一個(gè)UIEvent對(duì)象傳遞到Appdelegate
  • 2.由Appdelegate向Application、UIWindow等向上傳遞事件
  • 3.視圖收到父響應(yīng)者傳遞的事件后,通過hitView判斷是否選中
  • 4.如果沒有判定中,那么不處理,如果判定中,遍歷子視圖,遞歸執(zhí)行3和4
  • 5.最后遞歸找到最頂層的button,最適合的視圖
  • 6.如果能響應(yīng),執(zhí)行它的交互響應(yīng) ,不能的話,遞歸到上一個(gè)響應(yīng)者,執(zhí)行響應(yīng) 。
  • 7.如果一直遞歸到appdelegate到都沒響應(yīng),則廢棄

不能響應(yīng)的原因 :

  • view.hidden = YES
  • view.alpha<0.01
  • view.userinterface = NO
  • 不添加交互事件并不是不能響應(yīng),只是默認(rèn)不做處理
響應(yīng)鏈層級(jí)
傳遞圖

3.hit:test流程

剛才我們說到響應(yīng)者需要將事件在響應(yīng)鏈上傳遞,在內(nèi)部是通過兩個(gè)方法進(jìn)行傳遞 pointinside 和hit test

1.首先對(duì)響應(yīng)鏈最底層的View(UIWindow)視圖進(jìn)行命中判定,調(diào)用hittest:withevent方法
2.如果判定不是該視圖,則返回nil,pointInside:withevent方法無效,如果命中,則根據(jù)pointInside, 返回是不是響應(yīng)區(qū)域,如果是,則遍歷該視圖的子視圖進(jìn)行hittest判定
3.重復(fù)2,知道找到最上層最合適的視圖,然后執(zhí)行事件

這張圖是盜的
假設(shè)用戶點(diǎn)擊了視圖E

1.首先touch會(huì)命中window,查出上級(jí)視圖是viewA
2.viewA判定在A中,然后向上遍歷子視圖B和C
3.B判定不在自己的視圖內(nèi),返回nil,B分支結(jié)束
4.C判定在自己的視圖內(nèi),向上遍歷D和E進(jìn)行判定
5.D判定不在視圖內(nèi),D分支結(jié)束
6.E判定在該視圖內(nèi),子視圖為nil,則E是最合適視圖

  1. E進(jìn)行響應(yīng),如果E無法響應(yīng),則執(zhí)行父視圖C的響應(yīng)

以上就是響應(yīng)鏈傳遞的流程,說完了流程現(xiàn)在來說說響應(yīng)鏈具體有何應(yīng)用

應(yīng)用一: 超區(qū)或者裁區(qū)響應(yīng)
image.png

對(duì)于這張圖片,一般簡(jiǎn)單做法就是方形視圖切圓角,這樣的話圓形周邊的四個(gè)角(紅色區(qū)域)也會(huì)響應(yīng),如果交互或者產(chǎn)品要求只能圓形響應(yīng)的話,這時(shí)候就需要重寫方法

#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__);
    //已經(jīng)知道是個(gè)正方形
    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

這段代碼要用到的是下面那個(gè)方法,進(jìn)行裁剪交互區(qū)域,返回可交互的圓形區(qū)域

按鈕超區(qū).png

這段圖片也是進(jìn)行超區(qū)處理

應(yīng)用二:通過響應(yīng)鏈進(jìn)行對(duì)象間交互
目前常用的數(shù)據(jù)/事件回傳有block、delegate、notification,各有所長(zhǎng)。響應(yīng)鏈具有逐層傳遞的特點(diǎn),可通過nextresponder取到下一個(gè)響應(yīng)者,基于這個(gè)特點(diǎn),可以設(shè)計(jì)通過鏈路進(jìn)行對(duì)象的數(shù)據(jù)回傳

具體做法

  • 1.通過UIResponder的一個(gè)category,定義一個(gè)方法,通過響應(yīng)鏈向底層傳遞
  • 2.通過extern nsstring const 方式定義交互事件的eventname名字(也可以硬編碼)
  • 3.以tableview為例,cell上有多個(gè)交互事件,在button的點(diǎn)擊事件里調(diào)用category方法
  • 4.在controller里面接收到上一層響應(yīng)者發(fā)來的信息,處理,若需要繼續(xù)傳遞(或穿透?jìng)鬟f) 則調(diào)用category的方法


    1-定義分類

    2-定義eventname

    3-在交互事件是執(zhí)行category

    4-在控制器里的操作
下層響應(yīng)者接受多個(gè)響應(yīng)事件的strategy模式

當(dāng)下層響應(yīng)者例如controller接受來自多個(gè)子視圖的事件時(shí),會(huì)導(dǎo)致判斷的if else冗余,這時(shí)可以采用strategy對(duì)每個(gè)eventname分類處理

解決辦法:定義一個(gè)字典,eventname做key,invocation做value
在routeEvent里面通過eventname取出strategy字典的value - invocation,
然后[invocation invoke]

這種方式要求每個(gè)eventname都對(duì)應(yīng)一個(gè)selector,如果event不是很多的話,
用if else 也沒什么關(guān)系
如下圖


定義event字典
事件調(diào)用的地方
  • 響應(yīng)鏈傳遞和代理block等的使用對(duì)比
image.png
參考文章
demo鏈接: https://github.com/MoonMD/ResponderDemo.git
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 好奇觸摸事件是如何從屏幕轉(zhuǎn)移到APP內(nèi)的?困惑于Cell怎么突然不能點(diǎn)擊了?糾結(jié)于如何實(shí)現(xiàn)這個(gè)奇葩響應(yīng)需求?亦或是...
    Lotheve閱讀 59,432評(píng)論 51 604
  • 在iOS開發(fā)中經(jīng)常會(huì)涉及到觸摸事件。本想自己總結(jié)一下,但是遇到了這篇文章,感覺總結(jié)的已經(jīng)很到位,特此轉(zhuǎn)載。作者:L...
    WQ_UESTC閱讀 6,237評(píng)論 4 26
  • 事件傳遞:響應(yīng)者鏈 當(dāng)你設(shè)計(jì)一個(gè)app的時(shí)候,你很可能需要你的app能夠動(dòng)態(tài)響應(yīng)某些事件。比如,觸摸可以發(fā)生在屏幕...
    hjfrun閱讀 1,121評(píng)論 1 5
  • 用戶以多種方式操縱他們的iOS設(shè)備,例如觸摸屏幕或搖動(dòng)設(shè)備。 iOS會(huì)解釋用戶何時(shí)以及如何操作硬件并將此信息傳遞到...
    坤坤同學(xué)閱讀 4,116評(píng)論 7 19
  • 在開發(fā)過程中,大家或多或少的都會(huì)碰到令人頭疼的手勢(shì)沖突問題,正好前兩天碰到一個(gè)類似的bug,于是借著這個(gè)機(jī)會(huì)了解了...
    閆仕偉閱讀 5,662評(píng)論 2 23

友情鏈接更多精彩內(nèi)容